From 45ff0898d0c412a23b3f263356bc7b45be485065 Mon Sep 17 00:00:00 2001 From: "Ricardo Minguez Pablos (RIDO)" Date: Sat, 7 Feb 2026 13:16:08 -0800 Subject: [PATCH 1/5] Add agentic identity support to ConversationClientTest Introduce agentic identity support in ConversationClientTest by adding helper methods to construct agentic user/app context from environment variables. Update all relevant test methods to use these helpers and pass agentic identity where required. Replace Console.WriteLine with xUnit output integration and configure logging for xUnit. Add MartinCostello.Logging.XUnit package for improved test logging. Mark tests requiring special permissions as skipped, and update logging configuration to use "Microsoft.Teams": "Trace". Includes minor test output and environment variable handling improvements. --- core/samples/CoreBot/appsettings.json | 2 +- .../CompatTeamsInfoTests.cs | 18 +- .../ConversationClientTest.cs | 186 +++++++++++++----- .../Microsoft.Teams.Bot.Core.Tests.csproj | 1 + .../TeamsApiClientTests.cs | 2 +- .../Microsoft.Teams.Bot.Core.Tests/readme.md | 5 +- 6 files changed, 156 insertions(+), 58 deletions(-) diff --git a/core/samples/CoreBot/appsettings.json b/core/samples/CoreBot/appsettings.json index 1ff8c135..396e887e 100644 --- a/core/samples/CoreBot/appsettings.json +++ b/core/samples/CoreBot/appsettings.json @@ -3,7 +3,7 @@ "Logging": { "LogLevel": { "Default": "Warning", - "Microsoft.Bot": "Trace" + "Microsoft.Teams": "Trace" } }, "AllowedHosts": "*" diff --git a/core/test/Microsoft.Teams.Bot.Core.Tests/CompatTeamsInfoTests.cs b/core/test/Microsoft.Teams.Bot.Core.Tests/CompatTeamsInfoTests.cs index 0546c7da..a919b14d 100644 --- a/core/test/Microsoft.Teams.Bot.Core.Tests/CompatTeamsInfoTests.cs +++ b/core/test/Microsoft.Teams.Bot.Core.Tests/CompatTeamsInfoTests.cs @@ -178,7 +178,7 @@ await adapter.ContinueConversationAsync( CancellationToken.None); } - [Fact] + [Fact(Skip = "Require special permissions")] public async Task GetMeetingInfoAsync_WithMeetingId_ReturnsMeetingInfo() { var adapter = InitializeCompatAdapter(); @@ -224,7 +224,7 @@ await adapter.ContinueConversationAsync( CancellationToken.None); } - [Fact] + [Fact(Skip = "Require special permissions")] public async Task SendMeetingNotificationAsync_SendsNotification() { var adapter = InitializeCompatAdapter(); @@ -323,7 +323,7 @@ await adapter.ContinueConversationAsync( CancellationToken.None); } - [Fact] + [Fact(Skip = "Require special permissions")] public async Task SendMessageToListOfUsersAsync_ReturnsOperationId() { var adapter = InitializeCompatAdapter(); @@ -362,7 +362,7 @@ await adapter.ContinueConversationAsync( CancellationToken.None); } - [Fact] + [Fact(Skip = "Require special permissions")] public async Task SendMessageToListOfChannelsAsync_ReturnsOperationId() { var adapter = InitializeCompatAdapter(); @@ -396,7 +396,7 @@ await adapter.ContinueConversationAsync( CancellationToken.None); } - [Fact] + [Fact(Skip = "Require special permissions")] public async Task SendMessageToAllUsersInTeamAsync_ReturnsOperationId() { var adapter = InitializeCompatAdapter(); @@ -455,7 +455,7 @@ await adapter.ContinueConversationAsync( CancellationToken.None); } - [Fact] + [Fact(Skip = "Require special permissions")] public async Task SendMessageToTeamsChannelAsync_CreatesConversationAndSendsMessage() { var adapter = InitializeCompatAdapter(); @@ -487,7 +487,7 @@ await adapter.ContinueConversationAsync( CancellationToken.None); } - [Fact] + [Fact(Skip = "Require special permissions")] public async Task GetOperationStateAsync_WithOperationId_ReturnsState() { var adapter = InitializeCompatAdapter(); @@ -510,7 +510,7 @@ await adapter.ContinueConversationAsync( CancellationToken.None); } - [Fact] + [Fact(Skip = "Require special permissions")] public async Task GetPagedFailedEntriesAsync_WithOperationId_ReturnsFailedEntries() { var adapter = InitializeCompatAdapter(); @@ -532,7 +532,7 @@ await adapter.ContinueConversationAsync( CancellationToken.None); } - [Fact] + [Fact(Skip = "Requires valid operation ID from batch operation")] public async Task CancelOperationAsync_WithOperationId_CancelsOperation() { var adapter = InitializeCompatAdapter(); diff --git a/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs b/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs index 85a583a6..6aab1f2a 100644 --- a/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs +++ b/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs @@ -1,11 +1,13 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using Microsoft.Teams.Bot.Core.Hosting; -using Microsoft.Teams.Bot.Core.Schema; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Teams.Bot.Core; +using Microsoft.Teams.Bot.Core.Hosting; +using Microsoft.Teams.Bot.Core.Schema; +using Xunit.Abstractions; namespace Microsoft.Bot.Core.Tests; @@ -14,9 +16,11 @@ public class ConversationClientTest private readonly ServiceProvider _serviceProvider; private readonly ConversationClient _conversationClient; private readonly Uri _serviceUrl; + private readonly ITestOutputHelper testOutput; - public ConversationClientTest() + public ConversationClientTest(ITestOutputHelper outputHelper) { + testOutput = outputHelper; IConfigurationBuilder builder = new ConfigurationBuilder() .SetBasePath(AppDomain.CurrentDomain.BaseDirectory) .AddEnvironmentVariables(); @@ -24,7 +28,12 @@ public ConversationClientTest() IConfiguration configuration = builder.Build(); ServiceCollection services = new(); - services.AddLogging(); + services.AddLogging((builder) => { + builder.AddXUnit(outputHelper); + builder.AddFilter("System.Net", LogLevel.Warning); + builder.AddFilter("Microsoft.Identity", LogLevel.Warning); + builder.AddFilter("Microsoft.Teams", LogLevel.Information); + }); services.AddSingleton(configuration); services.AddBotApplication(); _serviceProvider = services.BuildServiceProvider(); @@ -40,6 +49,28 @@ public async Task SendActivityDefault() Type = ActivityType.Message, Properties = { { "text", $"Message from Automated tests, running in SDK `{BotApplication.Version}` at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, + From = GetConversationAccountWithAgenticProperties(), + Conversation = new() + { + Id = Environment.GetEnvironmentVariable("TEST_CONVERSATIONID") ?? throw new InvalidOperationException("TEST_ConversationId environment variable not set") + } + }; + SendActivityResponse res = await _conversationClient.SendActivityAsync(activity, cancellationToken: CancellationToken.None); + Assert.NotNull(res); + Assert.NotNull(res.Id); + } + + + + [Fact] + public async Task SendActivityDefaultWithAgentic() + { + CoreActivity activity = new() + { + Type = ActivityType.Message, + Properties = { { "text", $"Message from Automated tests, running in SDK `{BotApplication.Version}` at `{DateTime.UtcNow:s}`" } }, + ServiceUrl = _serviceUrl, + From = GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = Environment.GetEnvironmentVariable("TEST_CONVERSATIONID") ?? throw new InvalidOperationException("TEST_ConversationId environment variable not set") @@ -59,6 +90,7 @@ public async Task SendActivityToChannel() Type = ActivityType.Message, Properties = { { "text", $"Message from Automated tests, running in SDK `{BotApplication.Version}` at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, + From = GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = Environment.GetEnvironmentVariable("TEST_CHANNELID") ?? throw new InvalidOperationException("TEST_CHANNELID environment variable not set") @@ -77,6 +109,7 @@ public async Task SendActivityToPersonalChat_FailsWithBad_ConversationId() Type = ActivityType.Message, Properties = { { "text", $"Message from Automated tests, running in SDK `{BotApplication.Version}` at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, + From = GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = "a:1" @@ -96,6 +129,7 @@ public async Task UpdateActivity() Type = ActivityType.Message, Properties = { { "text", $"Original message from Automated tests at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, + From = GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = Environment.GetEnvironmentVariable("TEST_CONVERSATIONID") ?? throw new InvalidOperationException("TEST_ConversationId environment variable not set") @@ -111,6 +145,7 @@ public async Task UpdateActivity() { Type = ActivityType.Message, Properties = { { "text", $"Updated message from Automated tests at `{DateTime.UtcNow:s}`" } }, + From = GetConversationAccountWithAgenticProperties(), ServiceUrl = _serviceUrl, }; @@ -133,6 +168,7 @@ public async Task DeleteActivity() Type = ActivityType.Message, Properties = { { "text", $"Message to delete from Automated tests at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, + From = GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = Environment.GetEnvironmentVariable("TEST_CONVERSATIONID") ?? throw new InvalidOperationException("TEST_ConversationId environment variable not set") @@ -151,6 +187,7 @@ await _conversationClient.DeleteActivityAsync( activity.Conversation.Id, sendResponse.Id, _serviceUrl, + GetAgenticIdentity(), cancellationToken: CancellationToken.None); // If no exception was thrown, the delete was successful @@ -164,16 +201,17 @@ public async Task GetConversationMembers() IList members = await _conversationClient.GetConversationMembersAsync( conversationId, _serviceUrl, + GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(members); Assert.NotEmpty(members); // Log members - Console.WriteLine($"Found {members.Count} members in conversation {conversationId}:"); + testOutput.WriteLine($"Found {members.Count} members in conversation {conversationId}:"); foreach (ConversationAccount member in members) { - Console.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); + testOutput.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); Assert.NotNull(member); Assert.NotNull(member.Id); } @@ -189,13 +227,14 @@ public async Task GetConversationMember() conversationId, userId, _serviceUrl, + GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(member); // Log member - Console.WriteLine($"Found member in conversation {conversationId}:"); - Console.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); + testOutput.WriteLine($"Found member in conversation {conversationId}:"); + testOutput.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); Assert.NotNull(member); Assert.NotNull(member.Id); } @@ -209,16 +248,17 @@ public async Task GetConversationMembersInChannel() IList members = await _conversationClient.GetConversationMembersAsync( channelId, _serviceUrl, + GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(members); Assert.NotEmpty(members); // Log members - Console.WriteLine($"Found {members.Count} members in channel {channelId}:"); + testOutput.WriteLine($"Found {members.Count} members in channel {channelId}:"); foreach (ConversationAccount member in members) { - Console.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); + testOutput.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); Assert.NotNull(member); Assert.NotNull(member.Id); } @@ -233,6 +273,7 @@ public async Task GetActivityMembers() Type = ActivityType.Message, Properties = { { "text", $"Message for GetActivityMembers test at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, + From = GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = Environment.GetEnvironmentVariable("TEST_CONVERSATIONID") ?? throw new InvalidOperationException("TEST_ConversationId environment variable not set") @@ -248,16 +289,17 @@ public async Task GetActivityMembers() activity.Conversation.Id, sendResponse.Id, _serviceUrl, + GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(members); Assert.NotEmpty(members); // Log activity members - Console.WriteLine($"Found {members.Count} members for activity {sendResponse.Id}:"); + testOutput.WriteLine($"Found {members.Count} members for activity {sendResponse.Id}:"); foreach (ConversationAccount member in members) { - Console.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); + testOutput.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); Assert.NotNull(member); Assert.NotNull(member.Id); } @@ -276,19 +318,19 @@ public async Task GetConversations() Assert.NotEmpty(response.Conversations); // Log conversations - Console.WriteLine($"Found {response.Conversations.Count} conversations:"); + testOutput.WriteLine($"Found {response.Conversations.Count} conversations:"); foreach (ConversationMembers conversation in response.Conversations) { - Console.WriteLine($" - Conversation Id: {conversation.Id}"); + testOutput.WriteLine($" - Conversation Id: {conversation.Id}"); Assert.NotNull(conversation); Assert.NotNull(conversation.Id); if (conversation.Members != null && conversation.Members.Any()) { - Console.WriteLine($" Members ({conversation.Members.Count}):"); + testOutput.WriteLine($" Members ({conversation.Members.Count}):"); foreach (ConversationAccount member in conversation.Members) { - Console.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); + testOutput.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); } } } @@ -315,14 +357,15 @@ public async Task CreateConversation_WithMembers() CreateConversationResponse response = await _conversationClient.CreateConversationAsync( parameters, _serviceUrl, + GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(response); Assert.NotNull(response.Id); - Console.WriteLine($"Created conversation: {response.Id}"); - Console.WriteLine($" ActivityId: {response.ActivityId}"); - Console.WriteLine($" ServiceUrl: {response.ServiceUrl}"); + testOutput.WriteLine($"Created conversation: {response.Id}"); + testOutput.WriteLine($" ActivityId: {response.ActivityId}"); + testOutput.WriteLine($" ServiceUrl: {response.ServiceUrl}"); // Send a message to the newly created conversation CoreActivity activity = new() @@ -340,7 +383,7 @@ public async Task CreateConversation_WithMembers() Assert.NotNull(sendResponse); Assert.NotNull(sendResponse.Id); - Console.WriteLine($" Sent message with activity ID: {sendResponse.Id}"); + testOutput.WriteLine($" Sent message with activity ID: {sendResponse.Id}"); } // TODO: This doesn't work @@ -368,12 +411,13 @@ public async Task CreateConversation_WithGroup() CreateConversationResponse response = await _conversationClient.CreateConversationAsync( parameters, _serviceUrl, + GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(response); Assert.NotNull(response.Id); - Console.WriteLine($"Created group conversation: {response.Id}"); + testOutput.WriteLine($"Created group conversation: {response.Id}"); // Send a message to the newly created group conversation CoreActivity activity = new() @@ -391,7 +435,7 @@ public async Task CreateConversation_WithGroup() Assert.NotNull(sendResponse); Assert.NotNull(sendResponse.Id); - Console.WriteLine($" Sent message with activity ID: {sendResponse.Id}"); + testOutput.WriteLine($" Sent message with activity ID: {sendResponse.Id}"); } // TODO: This doesn't work @@ -421,7 +465,7 @@ public async Task CreateConversation_WithTopicName() Assert.NotNull(response); Assert.NotNull(response.Id); - Console.WriteLine($"Created conversation with topic '{parameters.TopicName}': {response.Id}"); + testOutput.WriteLine($"Created conversation with topic '{parameters.TopicName}': {response.Id}"); // Send a message to the newly created conversation CoreActivity activity = new() @@ -439,7 +483,7 @@ public async Task CreateConversation_WithTopicName() Assert.NotNull(sendResponse); Assert.NotNull(sendResponse.Id); - Console.WriteLine($" Sent message with activity ID: {sendResponse.Id}"); + testOutput.WriteLine($" Sent message with activity ID: {sendResponse.Id}"); } // TODO: This doesn't fail, but doesn't actually create the initial activity @@ -468,14 +512,15 @@ public async Task CreateConversation_WithInitialActivity() CreateConversationResponse response = await _conversationClient.CreateConversationAsync( parameters, _serviceUrl, + GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(response); Assert.NotNull(response.Id); // Assert.NotNull(response.ActivityId); // Should have an activity ID since we sent an initial message - Console.WriteLine($"Created conversation with initial activity: {response.Id}"); - Console.WriteLine($" Initial activity ID: {response.ActivityId}"); + testOutput.WriteLine($"Created conversation with initial activity: {response.Id}"); + testOutput.WriteLine($" Initial activity ID: {response.ActivityId}"); } [Fact] @@ -502,12 +547,13 @@ public async Task CreateConversation_WithChannelData() CreateConversationResponse response = await _conversationClient.CreateConversationAsync( parameters, _serviceUrl, + GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(response); Assert.NotNull(response.Id); - Console.WriteLine($"Created conversation with channel data: {response.Id}"); + testOutput.WriteLine($"Created conversation with channel data: {response.Id}"); } [Fact] @@ -518,23 +564,26 @@ public async Task GetConversationPagedMembers() PagedMembersResult result = await _conversationClient.GetConversationPagedMembersAsync( conversationId, _serviceUrl, + 10, + null!, + GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(result); Assert.NotNull(result.Members); Assert.NotEmpty(result.Members); - Console.WriteLine($"Found {result.Members.Count} members in page:"); + testOutput.WriteLine($"Found {result.Members.Count} members in page:"); foreach (ConversationAccount member in result.Members) { - Console.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); + testOutput.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); Assert.NotNull(member); Assert.NotNull(member.Id); } if (!string.IsNullOrWhiteSpace(result.ContinuationToken)) { - Console.WriteLine($"Continuation token: {result.ContinuationToken}"); + testOutput.WriteLine($"Continuation token: {result.ContinuationToken}"); } } @@ -554,16 +603,16 @@ public async Task GetConversationPagedMembers_WithPageSize() Assert.NotEmpty(result.Members); Assert.Single(result.Members); - Console.WriteLine($"Found {result.Members.Count} members with pageSize=1:"); + testOutput.WriteLine($"Found {result.Members.Count} members with pageSize=1:"); foreach (ConversationAccount member in result.Members) { - Console.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); + testOutput.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); } // If there's a continuation token, get the next page if (!string.IsNullOrWhiteSpace(result.ContinuationToken)) { - Console.WriteLine($"Getting next page with continuation token..."); + testOutput.WriteLine($"Getting next page with continuation token..."); PagedMembersResult nextPage = await _conversationClient.GetConversationPagedMembersAsync( conversationId, @@ -575,10 +624,10 @@ public async Task GetConversationPagedMembers_WithPageSize() Assert.NotNull(nextPage); Assert.NotNull(nextPage.Members); - Console.WriteLine($"Found {nextPage.Members.Count} members in next page:"); + testOutput.WriteLine($"Found {nextPage.Members.Count} members in next page:"); foreach (ConversationAccount member in nextPage.Members) { - Console.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); + testOutput.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); } } } @@ -597,10 +646,10 @@ public async Task DeleteConversationMember() Assert.NotNull(membersBefore); Assert.NotEmpty(membersBefore); - Console.WriteLine($"Members before deletion: {membersBefore.Count}"); + testOutput.WriteLine($"Members before deletion: {membersBefore.Count}"); foreach (ConversationAccount member in membersBefore) { - Console.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); + testOutput.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); } // Delete the test user @@ -615,7 +664,7 @@ await _conversationClient.DeleteConversationMemberAsync( _serviceUrl, cancellationToken: CancellationToken.None); - Console.WriteLine($"Deleted member: {memberToDelete}"); + testOutput.WriteLine($"Deleted member: {memberToDelete}"); // Get members after deletion IList membersAfter = await _conversationClient.GetConversationMembersAsync( @@ -625,10 +674,10 @@ await _conversationClient.DeleteConversationMemberAsync( Assert.NotNull(membersAfter); - Console.WriteLine($"Members after deletion: {membersAfter.Count}"); + testOutput.WriteLine($"Members after deletion: {membersAfter.Count}"); foreach (ConversationAccount member in membersAfter) { - Console.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); + testOutput.WriteLine($" - Id: {member.Id}, Name: {member.Name}"); } // Verify the member was deleted @@ -680,8 +729,8 @@ public async Task SendConversationHistory() Assert.NotNull(response); - Console.WriteLine($"Sent conversation history with {transcript.Activities?.Count} activities"); - Console.WriteLine($"Response ID: {response.Id}"); + testOutput.WriteLine($"Sent conversation history with {transcript.Activities?.Count} activities"); + testOutput.WriteLine($"Response ID: {response.Id}"); } [Fact(Skip = "Attachment upload endpoint not found")] @@ -709,9 +758,54 @@ public async Task UploadAttachment() Assert.NotNull(response); Assert.NotNull(response.Id); - Console.WriteLine($"Uploaded attachment: {attachmentData.Name}"); - Console.WriteLine($" Attachment ID: {response.Id}"); - Console.WriteLine($" Content-Type: {attachmentData.Type}"); - Console.WriteLine($" Size: {fileBytes.Length} bytes"); + testOutput.WriteLine($"Uploaded attachment: {attachmentData.Name}"); + testOutput.WriteLine($" Attachment ID: {response.Id}"); + testOutput.WriteLine($" Content-Type: {attachmentData.Type}"); + testOutput.WriteLine($" Size: {fileBytes.Length} bytes"); + } + + private ConversationAccount GetConversationAccountWithAgenticProperties() + { + string agenticUserId = Environment.GetEnvironmentVariable("TEST_AGENTIC_USERID"); + string agenticAppId = Environment.GetEnvironmentVariable("TEST_AGENTIC_APPID"); + string agenticAppBlueprintId = Environment.GetEnvironmentVariable("AzureAd__ClientId"); + + if (string.IsNullOrEmpty(agenticUserId)) + { + return new ConversationAccount(); + } + + ConversationAccount account = new() + { + Id = agenticUserId, + Name = "Agentic User", + Properties = + { + { "agenticUserId", agenticUserId }, + { "agenticAppId", agenticAppId }, + { "agenticAppBlueprintId", agenticAppBlueprintId } + } + }; + return account; + } + + private AgenticIdentity GetAgenticIdentity() + { + string agenticUserId = Environment.GetEnvironmentVariable("TEST_AGENTIC_USERID"); + string agenticAppId = Environment.GetEnvironmentVariable("TEST_AGENTIC_APPID"); + string agenticAppBlueprintId = Environment.GetEnvironmentVariable("AzureAd__ClientId"); + + if (string.IsNullOrEmpty(agenticUserId)) + { + return null!; + } + + AgenticIdentity identity = new() + { + AgenticUserId = agenticUserId, + AgenticAppId = agenticAppId, + AgenticAppBlueprintId = agenticAppBlueprintId + }; + return identity; } } diff --git a/core/test/Microsoft.Teams.Bot.Core.Tests/Microsoft.Teams.Bot.Core.Tests.csproj b/core/test/Microsoft.Teams.Bot.Core.Tests/Microsoft.Teams.Bot.Core.Tests.csproj index b7aad5b2..722bb12d 100644 --- a/core/test/Microsoft.Teams.Bot.Core.Tests/Microsoft.Teams.Bot.Core.Tests.csproj +++ b/core/test/Microsoft.Teams.Bot.Core.Tests/Microsoft.Teams.Bot.Core.Tests.csproj @@ -11,6 +11,7 @@ + diff --git a/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs b/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs index 861a4ad2..a3dfe5dd 100644 --- a/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs +++ b/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs @@ -98,7 +98,7 @@ await Assert.ThrowsAsync(() #region Meeting Operations Tests - [Fact] + [Fact(Skip = "Batch operations require special permissions")] public async Task FetchMeetingInfo() { string meetingId = Environment.GetEnvironmentVariable("TEST_MEETINGID") ?? throw new InvalidOperationException("TEST_MEETINGID environment variable not set"); diff --git a/core/test/Microsoft.Teams.Bot.Core.Tests/readme.md b/core/test/Microsoft.Teams.Bot.Core.Tests/readme.md index 125a5289..4fb52089 100644 --- a/core/test/Microsoft.Teams.Bot.Core.Tests/readme.md +++ b/core/test/Microsoft.Teams.Bot.Core.Tests/readme.md @@ -8,6 +8,9 @@ To run these tests we need to configure the environment variables using a `.runs + 0d5eb8a3-1642-4e63-9ccc-a89aa461716c + 3fc62d4f-b04e-4c71-878b-02a2fa395fe2 + https://botapi.skype.com/.default a:17vxw6pGQOb3Zfh8acXT8m_PqHycYpaFgzu2mFMUfkT-h0UskMctq5ZPPc7FIQxn2bx7rBSm5yE_HeUXsCcKZBrv77RgorB3_1_pAdvMhi39ClxQgawzyQ9GBFkdiwOxT https://login.microsoftonline.com/ @@ -18,4 +21,4 @@ To run these tests we need to configure the environment variables using a `.runs -``` \ No newline at end of file +``` From 73a7f3725e0ad82f5a41479cffcec79f0237f242 Mon Sep 17 00:00:00 2001 From: "Ricardo Minguez Pablos (RIDO)" Date: Sun, 8 Feb 2026 21:24:24 -0800 Subject: [PATCH 2/5] Refactor: use var for env variable declarations Replaced explicit string declarations with var for agenticUserId, agenticAppId, and agenticAppBlueprintId in GetConversationAccountWithAgenticProperties and GetAgenticIdentity methods. This change improves code readability and maintains stylistic consistency. No functional changes were made. --- .../ConversationClientTest.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs b/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs index 6aab1f2a..d1a52f5d 100644 --- a/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs +++ b/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs @@ -766,9 +766,9 @@ public async Task UploadAttachment() private ConversationAccount GetConversationAccountWithAgenticProperties() { - string agenticUserId = Environment.GetEnvironmentVariable("TEST_AGENTIC_USERID"); - string agenticAppId = Environment.GetEnvironmentVariable("TEST_AGENTIC_APPID"); - string agenticAppBlueprintId = Environment.GetEnvironmentVariable("AzureAd__ClientId"); + var agenticUserId = Environment.GetEnvironmentVariable("TEST_AGENTIC_USERID"); + var agenticAppId = Environment.GetEnvironmentVariable("TEST_AGENTIC_APPID"); + var agenticAppBlueprintId = Environment.GetEnvironmentVariable("AzureAd__ClientId"); if (string.IsNullOrEmpty(agenticUserId)) { @@ -791,9 +791,9 @@ private ConversationAccount GetConversationAccountWithAgenticProperties() private AgenticIdentity GetAgenticIdentity() { - string agenticUserId = Environment.GetEnvironmentVariable("TEST_AGENTIC_USERID"); - string agenticAppId = Environment.GetEnvironmentVariable("TEST_AGENTIC_APPID"); - string agenticAppBlueprintId = Environment.GetEnvironmentVariable("AzureAd__ClientId"); + var agenticUserId = Environment.GetEnvironmentVariable("TEST_AGENTIC_USERID"); + var agenticAppId = Environment.GetEnvironmentVariable("TEST_AGENTIC_APPID"); + var agenticAppBlueprintId = Environment.GetEnvironmentVariable("AzureAd__ClientId"); if (string.IsNullOrEmpty(agenticUserId)) { From c1fe33c28bf1d8656a1dff6c127593135a472ded Mon Sep 17 00:00:00 2001 From: "Ricardo Minguez Pablos (RIDO)" Date: Sun, 8 Feb 2026 22:04:06 -0800 Subject: [PATCH 3/5] Refactor agentic identity retrieval in test code Centralize agentic identity and conversation account construction in new AgenticIdentitiyFromEnv helper. Replace inlined and private methods in test files with calls to this helper. Remove redundant methods from ConversationClientTest. Update TeamsApiClientTests to use ITestOutputHelper for logging and consistently pass agentic identity to TeamsApiClient methods. Improves code reuse, test output, and maintainability. --- .../AgenticIdentitiyFromEnv.cs | 59 +++++++ .../ConversationClientTest.cs | 82 +++------ .../TeamsApiClientTests.cs | 163 ++++++++++-------- 3 files changed, 172 insertions(+), 132 deletions(-) create mode 100644 core/test/Microsoft.Teams.Bot.Core.Tests/AgenticIdentitiyFromEnv.cs diff --git a/core/test/Microsoft.Teams.Bot.Core.Tests/AgenticIdentitiyFromEnv.cs b/core/test/Microsoft.Teams.Bot.Core.Tests/AgenticIdentitiyFromEnv.cs new file mode 100644 index 00000000..6e39dd3f --- /dev/null +++ b/core/test/Microsoft.Teams.Bot.Core.Tests/AgenticIdentitiyFromEnv.cs @@ -0,0 +1,59 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Teams.Bot.Core.Schema; + +namespace Microsoft.Teams.Bot.Core.Tests +{ + internal class AgenticIdentitiyFromEnv + { + + internal static ConversationAccount GetConversationAccountWithAgenticProperties() + { + var agenticUserId = Environment.GetEnvironmentVariable("TEST_AGENTIC_USERID"); + var agenticAppId = Environment.GetEnvironmentVariable("TEST_AGENTIC_APPID"); + var agenticAppBlueprintId = Environment.GetEnvironmentVariable("AzureAd__ClientId"); + + if (string.IsNullOrEmpty(agenticUserId)) + { + return new ConversationAccount(); + } + + ConversationAccount account = new() + { + Id = agenticUserId, + Name = "Agentic User", + Properties = + { + { "agenticUserId", agenticUserId }, + { "agenticAppId", agenticAppId }, + { "agenticAppBlueprintId", agenticAppBlueprintId } + } + }; + return account; + } + + internal static AgenticIdentity GetAgenticIdentity() + { + var agenticUserId = Environment.GetEnvironmentVariable("TEST_AGENTIC_USERID"); + var agenticAppId = Environment.GetEnvironmentVariable("TEST_AGENTIC_APPID"); + var agenticAppBlueprintId = Environment.GetEnvironmentVariable("AzureAd__ClientId"); + + if (string.IsNullOrEmpty(agenticUserId)) + { + return null!; + } + + AgenticIdentity identity = new() + { + AgenticUserId = agenticUserId, + AgenticAppId = agenticAppId, + AgenticAppBlueprintId = agenticAppBlueprintId + }; + return identity; + } + } +} diff --git a/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs b/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs index d1a52f5d..ff9aad1d 100644 --- a/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs +++ b/core/test/Microsoft.Teams.Bot.Core.Tests/ConversationClientTest.cs @@ -7,6 +7,7 @@ using Microsoft.Teams.Bot.Core; using Microsoft.Teams.Bot.Core.Hosting; using Microsoft.Teams.Bot.Core.Schema; +using Microsoft.Teams.Bot.Core.Tests; using Xunit.Abstractions; namespace Microsoft.Bot.Core.Tests; @@ -49,7 +50,7 @@ public async Task SendActivityDefault() Type = ActivityType.Message, Properties = { { "text", $"Message from Automated tests, running in SDK `{BotApplication.Version}` at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, - From = GetConversationAccountWithAgenticProperties(), + From = AgenticIdentitiyFromEnv.GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = Environment.GetEnvironmentVariable("TEST_CONVERSATIONID") ?? throw new InvalidOperationException("TEST_ConversationId environment variable not set") @@ -70,7 +71,7 @@ public async Task SendActivityDefaultWithAgentic() Type = ActivityType.Message, Properties = { { "text", $"Message from Automated tests, running in SDK `{BotApplication.Version}` at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, - From = GetConversationAccountWithAgenticProperties(), + From = AgenticIdentitiyFromEnv.GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = Environment.GetEnvironmentVariable("TEST_CONVERSATIONID") ?? throw new InvalidOperationException("TEST_ConversationId environment variable not set") @@ -90,7 +91,7 @@ public async Task SendActivityToChannel() Type = ActivityType.Message, Properties = { { "text", $"Message from Automated tests, running in SDK `{BotApplication.Version}` at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, - From = GetConversationAccountWithAgenticProperties(), + From = AgenticIdentitiyFromEnv.GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = Environment.GetEnvironmentVariable("TEST_CHANNELID") ?? throw new InvalidOperationException("TEST_CHANNELID environment variable not set") @@ -109,7 +110,7 @@ public async Task SendActivityToPersonalChat_FailsWithBad_ConversationId() Type = ActivityType.Message, Properties = { { "text", $"Message from Automated tests, running in SDK `{BotApplication.Version}` at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, - From = GetConversationAccountWithAgenticProperties(), + From = AgenticIdentitiyFromEnv.GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = "a:1" @@ -129,7 +130,7 @@ public async Task UpdateActivity() Type = ActivityType.Message, Properties = { { "text", $"Original message from Automated tests at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, - From = GetConversationAccountWithAgenticProperties(), + From = AgenticIdentitiyFromEnv.GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = Environment.GetEnvironmentVariable("TEST_CONVERSATIONID") ?? throw new InvalidOperationException("TEST_ConversationId environment variable not set") @@ -145,7 +146,7 @@ public async Task UpdateActivity() { Type = ActivityType.Message, Properties = { { "text", $"Updated message from Automated tests at `{DateTime.UtcNow:s}`" } }, - From = GetConversationAccountWithAgenticProperties(), + From = AgenticIdentitiyFromEnv.GetConversationAccountWithAgenticProperties(), ServiceUrl = _serviceUrl, }; @@ -168,7 +169,7 @@ public async Task DeleteActivity() Type = ActivityType.Message, Properties = { { "text", $"Message to delete from Automated tests at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, - From = GetConversationAccountWithAgenticProperties(), + From = AgenticIdentitiyFromEnv.GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = Environment.GetEnvironmentVariable("TEST_CONVERSATIONID") ?? throw new InvalidOperationException("TEST_ConversationId environment variable not set") @@ -187,7 +188,7 @@ await _conversationClient.DeleteActivityAsync( activity.Conversation.Id, sendResponse.Id, _serviceUrl, - GetAgenticIdentity(), + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); // If no exception was thrown, the delete was successful @@ -201,7 +202,7 @@ public async Task GetConversationMembers() IList members = await _conversationClient.GetConversationMembersAsync( conversationId, _serviceUrl, - GetAgenticIdentity(), + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(members); @@ -227,7 +228,7 @@ public async Task GetConversationMember() conversationId, userId, _serviceUrl, - GetAgenticIdentity(), + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(member); @@ -248,7 +249,7 @@ public async Task GetConversationMembersInChannel() IList members = await _conversationClient.GetConversationMembersAsync( channelId, _serviceUrl, - GetAgenticIdentity(), + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(members); @@ -273,7 +274,7 @@ public async Task GetActivityMembers() Type = ActivityType.Message, Properties = { { "text", $"Message for GetActivityMembers test at `{DateTime.UtcNow:s}`" } }, ServiceUrl = _serviceUrl, - From = GetConversationAccountWithAgenticProperties(), + From = AgenticIdentitiyFromEnv.GetConversationAccountWithAgenticProperties(), Conversation = new() { Id = Environment.GetEnvironmentVariable("TEST_CONVERSATIONID") ?? throw new InvalidOperationException("TEST_ConversationId environment variable not set") @@ -289,7 +290,7 @@ public async Task GetActivityMembers() activity.Conversation.Id, sendResponse.Id, _serviceUrl, - GetAgenticIdentity(), + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(members); @@ -357,7 +358,7 @@ public async Task CreateConversation_WithMembers() CreateConversationResponse response = await _conversationClient.CreateConversationAsync( parameters, _serviceUrl, - GetAgenticIdentity(), + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(response); @@ -411,7 +412,7 @@ public async Task CreateConversation_WithGroup() CreateConversationResponse response = await _conversationClient.CreateConversationAsync( parameters, _serviceUrl, - GetAgenticIdentity(), + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(response); @@ -512,7 +513,7 @@ public async Task CreateConversation_WithInitialActivity() CreateConversationResponse response = await _conversationClient.CreateConversationAsync( parameters, _serviceUrl, - GetAgenticIdentity(), + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(response); @@ -547,7 +548,7 @@ public async Task CreateConversation_WithChannelData() CreateConversationResponse response = await _conversationClient.CreateConversationAsync( parameters, _serviceUrl, - GetAgenticIdentity(), + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(response); @@ -566,7 +567,7 @@ public async Task GetConversationPagedMembers() _serviceUrl, 10, null!, - GetAgenticIdentity(), + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(result); @@ -764,48 +765,5 @@ public async Task UploadAttachment() testOutput.WriteLine($" Size: {fileBytes.Length} bytes"); } - private ConversationAccount GetConversationAccountWithAgenticProperties() - { - var agenticUserId = Environment.GetEnvironmentVariable("TEST_AGENTIC_USERID"); - var agenticAppId = Environment.GetEnvironmentVariable("TEST_AGENTIC_APPID"); - var agenticAppBlueprintId = Environment.GetEnvironmentVariable("AzureAd__ClientId"); - - if (string.IsNullOrEmpty(agenticUserId)) - { - return new ConversationAccount(); - } - - ConversationAccount account = new() - { - Id = agenticUserId, - Name = "Agentic User", - Properties = - { - { "agenticUserId", agenticUserId }, - { "agenticAppId", agenticAppId }, - { "agenticAppBlueprintId", agenticAppBlueprintId } - } - }; - return account; - } - - private AgenticIdentity GetAgenticIdentity() - { - var agenticUserId = Environment.GetEnvironmentVariable("TEST_AGENTIC_USERID"); - var agenticAppId = Environment.GetEnvironmentVariable("TEST_AGENTIC_APPID"); - var agenticAppBlueprintId = Environment.GetEnvironmentVariable("AzureAd__ClientId"); - - if (string.IsNullOrEmpty(agenticUserId)) - { - return null!; - } - - AgenticIdentity identity = new() - { - AgenticUserId = agenticUserId, - AgenticAppId = agenticAppId, - AgenticAppBlueprintId = agenticAppBlueprintId - }; - return identity; - } + } diff --git a/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs b/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs index a3dfe5dd..1e115287 100644 --- a/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs +++ b/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs @@ -1,12 +1,15 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -using Microsoft.Teams.Bot.Core; -using Microsoft.Teams.Bot.Core.Hosting; -using Microsoft.Teams.Bot.Core.Schema; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Microsoft.Teams.Bot.Apps; +using Microsoft.Teams.Bot.Core; +using Microsoft.Teams.Bot.Core.Hosting; +using Microsoft.Teams.Bot.Core.Schema; +using Microsoft.Teams.Bot.Core.Tests; +using Xunit.Abstractions; namespace Microsoft.Bot.Core.Tests; @@ -15,9 +18,11 @@ public class TeamsApiClientTests private readonly ServiceProvider _serviceProvider; private readonly TeamsApiClient _teamsClient; private readonly Uri _serviceUrl; + private readonly ITestOutputHelper testOutput; - public TeamsApiClientTests() + public TeamsApiClientTests(ITestOutputHelper outputHelper) { + testOutput = outputHelper; IConfigurationBuilder builder = new ConfigurationBuilder() .SetBasePath(AppDomain.CurrentDomain.BaseDirectory) .AddEnvironmentVariables(); @@ -25,7 +30,12 @@ public TeamsApiClientTests() IConfiguration configuration = builder.Build(); ServiceCollection services = new(); - services.AddLogging(); + services.AddLogging((builder) => { + builder.AddXUnit(outputHelper); + builder.AddFilter("System.Net", LogLevel.Warning); + builder.AddFilter("Microsoft.Identity", LogLevel.Warning); + builder.AddFilter("Microsoft.Teams", LogLevel.Information); + }); services.AddSingleton(configuration); services.AddTeamsBotApplication(); _serviceProvider = services.BuildServiceProvider(); @@ -43,16 +53,17 @@ public async Task FetchChannelList() ChannelList result = await _teamsClient.FetchChannelListAsync( teamId, _serviceUrl, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(result); Assert.NotNull(result.Channels); Assert.NotEmpty(result.Channels); - Console.WriteLine($"Found {result.Channels.Count} channels in team {teamId}:"); + testOutput.WriteLine($"Found {result.Channels.Count} channels in team {teamId}:"); foreach (var channel in result.Channels) { - Console.WriteLine($" - Id: {channel.Id}, Name: {channel.Name}"); + testOutput.WriteLine($" - Id: {channel.Id}, Name: {channel.Name}"); Assert.NotNull(channel); Assert.NotNull(channel.Id); } @@ -62,7 +73,7 @@ public async Task FetchChannelList() public async Task FetchChannelList_FailsWithInvalidTeamId() { await Assert.ThrowsAsync(() - => _teamsClient.FetchChannelListAsync("invalid-team-id", _serviceUrl)); + => _teamsClient.FetchChannelListAsync("invalid-team-id", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] @@ -73,25 +84,26 @@ public async Task FetchTeamDetails() TeamDetails result = await _teamsClient.FetchTeamDetailsAsync( teamId, _serviceUrl, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(result); Assert.NotNull(result.Id); - Console.WriteLine($"Team details for {teamId}:"); - Console.WriteLine($" - Id: {result.Id}"); - Console.WriteLine($" - Name: {result.Name}"); - Console.WriteLine($" - AAD Group Id: {result.AadGroupId}"); - Console.WriteLine($" - Channel Count: {result.ChannelCount}"); - Console.WriteLine($" - Member Count: {result.MemberCount}"); - Console.WriteLine($" - Type: {result.Type}"); + testOutput.WriteLine($"Team details for {teamId}:"); + testOutput.WriteLine($" - Id: {result.Id}"); + testOutput.WriteLine($" - Name: {result.Name}"); + testOutput.WriteLine($" - AAD Group Id: {result.AadGroupId}"); + testOutput.WriteLine($" - Channel Count: {result.ChannelCount}"); + testOutput.WriteLine($" - Member Count: {result.MemberCount}"); + testOutput.WriteLine($" - Type: {result.Type}"); } [Fact] public async Task FetchTeamDetails_FailsWithInvalidTeamId() { await Assert.ThrowsAsync(() - => _teamsClient.FetchTeamDetailsAsync("invalid-team-id", _serviceUrl)); + => _teamsClient.FetchTeamDetailsAsync("invalid-team-id", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } #endregion @@ -106,24 +118,25 @@ public async Task FetchMeetingInfo() MeetingInfo result = await _teamsClient.FetchMeetingInfoAsync( meetingId, _serviceUrl, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(result); //Assert.NotNull(result.Id); - Console.WriteLine($"Meeting info for {meetingId}:"); + testOutput.WriteLine($"Meeting info for {meetingId}:"); if (result.Details != null) { - Console.WriteLine($" - Title: {result.Details.Title}"); - Console.WriteLine($" - Type: {result.Details.Type}"); - Console.WriteLine($" - Join URL: {result.Details.JoinUrl}"); - Console.WriteLine($" - Scheduled Start: {result.Details.ScheduledStartTime}"); - Console.WriteLine($" - Scheduled End: {result.Details.ScheduledEndTime}"); + testOutput.WriteLine($" - Title: {result.Details.Title}"); + testOutput.WriteLine($" - Type: {result.Details.Type}"); + testOutput.WriteLine($" - Join URL: {result.Details.JoinUrl}"); + testOutput.WriteLine($" - Scheduled Start: {result.Details.ScheduledStartTime}"); + testOutput.WriteLine($" - Scheduled End: {result.Details.ScheduledEndTime}"); } if (result.Organizer != null) { - Console.WriteLine($" - Organizer: {result.Organizer.Name} ({result.Organizer.Id})"); + testOutput.WriteLine($" - Organizer: {result.Organizer.Name} ({result.Organizer.Id})"); } } @@ -146,20 +159,21 @@ public async Task FetchParticipant() participantId, tenantId, _serviceUrl, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(result); - Console.WriteLine($"Participant info for {participantId} in meeting {meetingId}:"); + testOutput.WriteLine($"Participant info for {participantId} in meeting {meetingId}:"); if (result.User != null) { - Console.WriteLine($" - User Id: {result.User.Id}"); - Console.WriteLine($" - User Name: {result.User.Name}"); + testOutput.WriteLine($" - User Id: {result.User.Id}"); + testOutput.WriteLine($" - User Name: {result.User.Name}"); } if (result.Meeting != null) { - Console.WriteLine($" - Role: {result.Meeting.Role}"); - Console.WriteLine($" - In Meeting: {result.Meeting.InMeeting}"); + testOutput.WriteLine($" - Role: {result.Meeting.Role}"); + testOutput.WriteLine($" - In Meeting: {result.Meeting.InMeeting}"); } } @@ -190,17 +204,18 @@ public async Task SendMeetingNotification() meetingId, notification, _serviceUrl, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(result); - Console.WriteLine($"Meeting notification sent to meeting {meetingId}"); + testOutput.WriteLine($"Meeting notification sent to meeting {meetingId}"); if (result.RecipientsFailureInfo != null && result.RecipientsFailureInfo.Count > 0) { - Console.WriteLine($"Failed recipients:"); + testOutput.WriteLine($"Failed recipients:"); foreach (var failure in result.RecipientsFailureInfo) { - Console.WriteLine($" - {failure.RecipientMri}: {failure.ErrorCode} - {failure.FailureReason}"); + testOutput.WriteLine($" - {failure.RecipientMri}: {failure.ErrorCode} - {failure.FailureReason}"); } } } @@ -231,12 +246,13 @@ public async Task SendMessageToListOfUsers() members, tenantId, _serviceUrl, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(operationId); Assert.NotEmpty(operationId); - Console.WriteLine($"Batch message sent. Operation ID: {operationId}"); + testOutput.WriteLine($"Batch message sent. Operation ID: {operationId}"); } [Fact(Skip = "Batch operations require special permissions")] @@ -254,12 +270,13 @@ public async Task SendMessageToAllUsersInTenant() activity, tenantId, _serviceUrl, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(operationId); Assert.NotEmpty(operationId); - Console.WriteLine($"Tenant-wide message sent. Operation ID: {operationId}"); + testOutput.WriteLine($"Tenant-wide message sent. Operation ID: {operationId}"); } [Fact(Skip = "Batch operations require special permissions")] @@ -279,12 +296,13 @@ public async Task SendMessageToAllUsersInTeam() teamId, tenantId, _serviceUrl, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(operationId); Assert.NotEmpty(operationId); - Console.WriteLine($"Team-wide message sent. Operation ID: {operationId}"); + testOutput.WriteLine($"Team-wide message sent. Operation ID: {operationId}"); } [Fact(Skip = "Batch operations require special permissions")] @@ -309,12 +327,13 @@ public async Task SendMessageToListOfChannels() channels, tenantId, _serviceUrl, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(operationId); Assert.NotEmpty(operationId); - Console.WriteLine($"Channel batch message sent. Operation ID: {operationId}"); + testOutput.WriteLine($"Channel batch message sent. Operation ID: {operationId}"); } #endregion @@ -329,24 +348,25 @@ public async Task GetOperationState() BatchOperationState result = await _teamsClient.GetOperationStateAsync( operationId, _serviceUrl, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(result); Assert.NotNull(result.State); - Console.WriteLine($"Operation state for {operationId}:"); - Console.WriteLine($" - State: {result.State}"); - Console.WriteLine($" - Total Entries: {result.TotalEntriesCount}"); + testOutput.WriteLine($"Operation state for {operationId}:"); + testOutput.WriteLine($" - State: {result.State}"); + testOutput.WriteLine($" - Total Entries: {result.TotalEntriesCount}"); if (result.StatusMap != null) { - Console.WriteLine($" - Success: {result.StatusMap.Success}"); - Console.WriteLine($" - Failed: {result.StatusMap.Failed}"); - Console.WriteLine($" - Throttled: {result.StatusMap.Throttled}"); - Console.WriteLine($" - Pending: {result.StatusMap.Pending}"); + testOutput.WriteLine($" - Success: {result.StatusMap.Success}"); + testOutput.WriteLine($" - Failed: {result.StatusMap.Failed}"); + testOutput.WriteLine($" - Throttled: {result.StatusMap.Throttled}"); + testOutput.WriteLine($" - Pending: {result.StatusMap.Pending}"); } if (result.RetryAfter != null) { - Console.WriteLine($" - Retry After: {result.RetryAfter}"); + testOutput.WriteLine($" - Retry After: {result.RetryAfter}"); } } @@ -354,7 +374,7 @@ public async Task GetOperationState() public async Task GetOperationState_FailsWithInvalidOperationId() { await Assert.ThrowsAsync(() - => _teamsClient.GetOperationStateAsync("invalid-operation-id", _serviceUrl)); + => _teamsClient.GetOperationStateAsync("invalid-operation-id", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact(Skip = "Requires valid operation ID from batch operation")] @@ -365,26 +385,28 @@ public async Task GetPagedFailedEntries() BatchFailedEntriesResponse result = await _teamsClient.GetPagedFailedEntriesAsync( operationId, _serviceUrl, + null, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); Assert.NotNull(result); - Console.WriteLine($"Failed entries for operation {operationId}:"); + testOutput.WriteLine($"Failed entries for operation {operationId}:"); if (result.FailedEntries != null && result.FailedEntries.Count > 0) { foreach (var entry in result.FailedEntries) { - Console.WriteLine($" - Id: {entry.Id}, Error: {entry.Error}"); + testOutput.WriteLine($" - Id: {entry.Id}, Error: {entry.Error}"); } } else { - Console.WriteLine(" No failed entries"); + testOutput.WriteLine(" No failed entries"); } if (!string.IsNullOrWhiteSpace(result.ContinuationToken)) { - Console.WriteLine($"Continuation token: {result.ContinuationToken}"); + testOutput.WriteLine($"Continuation token: {result.ContinuationToken}"); } } @@ -396,9 +418,10 @@ public async Task CancelOperation() await _teamsClient.CancelOperationAsync( operationId, _serviceUrl, + AgenticIdentitiyFromEnv.GetAgenticIdentity(), cancellationToken: CancellationToken.None); - Console.WriteLine($"Operation {operationId} cancelled successfully"); + testOutput.WriteLine($"Operation {operationId} cancelled successfully"); } #endregion @@ -409,56 +432,56 @@ await _teamsClient.CancelOperationAsync( public async Task FetchChannelList_ThrowsOnNullTeamId() { await Assert.ThrowsAsync(() - => _teamsClient.FetchChannelListAsync(null!, _serviceUrl)); + => _teamsClient.FetchChannelListAsync(null!, _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task FetchChannelList_ThrowsOnEmptyTeamId() { await Assert.ThrowsAsync(() - => _teamsClient.FetchChannelListAsync("", _serviceUrl)); + => _teamsClient.FetchChannelListAsync("", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task FetchChannelList_ThrowsOnNullServiceUrl() { await Assert.ThrowsAsync(() - => _teamsClient.FetchChannelListAsync("team-id", null!)); + => _teamsClient.FetchChannelListAsync("team-id", null!, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task FetchTeamDetails_ThrowsOnNullTeamId() { await Assert.ThrowsAsync(() - => _teamsClient.FetchTeamDetailsAsync(null!, _serviceUrl)); + => _teamsClient.FetchTeamDetailsAsync(null!, _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task FetchMeetingInfo_ThrowsOnNullMeetingId() { await Assert.ThrowsAsync(() - => _teamsClient.FetchMeetingInfoAsync(null!, _serviceUrl)); + => _teamsClient.FetchMeetingInfoAsync(null!, _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task FetchParticipant_ThrowsOnNullMeetingId() { await Assert.ThrowsAsync(() - => _teamsClient.FetchParticipantAsync(null!, "participant", "tenant", _serviceUrl)); + => _teamsClient.FetchParticipantAsync(null!, "participant", "tenant", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task FetchParticipant_ThrowsOnNullParticipantId() { await Assert.ThrowsAsync(() - => _teamsClient.FetchParticipantAsync("meeting", null!, "tenant", _serviceUrl)); + => _teamsClient.FetchParticipantAsync("meeting", null!, "tenant", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task FetchParticipant_ThrowsOnNullTenantId() { await Assert.ThrowsAsync(() - => _teamsClient.FetchParticipantAsync("meeting", "participant", null!, _serviceUrl)); + => _teamsClient.FetchParticipantAsync("meeting", "participant", null!, _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] @@ -466,21 +489,21 @@ public async Task SendMeetingNotification_ThrowsOnNullMeetingId() { var notification = new TargetedMeetingNotification(); await Assert.ThrowsAsync(() - => _teamsClient.SendMeetingNotificationAsync(null!, notification, _serviceUrl)); + => _teamsClient.SendMeetingNotificationAsync(null!, notification, _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task SendMeetingNotification_ThrowsOnNullNotification() { await Assert.ThrowsAsync(() - => _teamsClient.SendMeetingNotificationAsync("meeting", null!, _serviceUrl)); + => _teamsClient.SendMeetingNotificationAsync("meeting", null!, _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task SendMessageToListOfUsers_ThrowsOnNullActivity() { await Assert.ThrowsAsync(() - => _teamsClient.SendMessageToListOfUsersAsync(null!, [new TeamMember("id")], "tenant", _serviceUrl)); + => _teamsClient.SendMessageToListOfUsersAsync(null!, [new TeamMember("id")], "tenant", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] @@ -488,7 +511,7 @@ public async Task SendMessageToListOfUsers_ThrowsOnNullMembers() { var activity = new CoreActivity { Type = ActivityType.Message }; await Assert.ThrowsAsync(() - => _teamsClient.SendMessageToListOfUsersAsync(activity, null!, "tenant", _serviceUrl)); + => _teamsClient.SendMessageToListOfUsersAsync(activity, null!, "tenant", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] @@ -496,14 +519,14 @@ public async Task SendMessageToListOfUsers_ThrowsOnEmptyMembers() { var activity = new CoreActivity { Type = ActivityType.Message }; await Assert.ThrowsAsync(() - => _teamsClient.SendMessageToListOfUsersAsync(activity, [], "tenant", _serviceUrl)); + => _teamsClient.SendMessageToListOfUsersAsync(activity, [], "tenant", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task SendMessageToAllUsersInTenant_ThrowsOnNullActivity() { await Assert.ThrowsAsync(() - => _teamsClient.SendMessageToAllUsersInTenantAsync(null!, "tenant", _serviceUrl)); + => _teamsClient.SendMessageToAllUsersInTenantAsync(null!, "tenant", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] @@ -511,14 +534,14 @@ public async Task SendMessageToAllUsersInTenant_ThrowsOnNullTenantId() { var activity = new CoreActivity { Type = ActivityType.Message }; await Assert.ThrowsAsync(() - => _teamsClient.SendMessageToAllUsersInTenantAsync(activity, null!, _serviceUrl)); + => _teamsClient.SendMessageToAllUsersInTenantAsync(activity, null!, _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task SendMessageToAllUsersInTeam_ThrowsOnNullActivity() { await Assert.ThrowsAsync(() - => _teamsClient.SendMessageToAllUsersInTeamAsync(null!, "team", "tenant", _serviceUrl)); + => _teamsClient.SendMessageToAllUsersInTeamAsync(null!, "team", "tenant", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] @@ -526,7 +549,7 @@ public async Task SendMessageToAllUsersInTeam_ThrowsOnNullTeamId() { var activity = new CoreActivity { Type = ActivityType.Message }; await Assert.ThrowsAsync(() - => _teamsClient.SendMessageToAllUsersInTeamAsync(activity, null!, "tenant", _serviceUrl)); + => _teamsClient.SendMessageToAllUsersInTeamAsync(activity, null!, "tenant", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] @@ -534,28 +557,28 @@ public async Task SendMessageToListOfChannels_ThrowsOnEmptyChannels() { var activity = new CoreActivity { Type = ActivityType.Message }; await Assert.ThrowsAsync(() - => _teamsClient.SendMessageToListOfChannelsAsync(activity, [], "tenant", _serviceUrl)); + => _teamsClient.SendMessageToListOfChannelsAsync(activity, [], "tenant", _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task GetOperationState_ThrowsOnNullOperationId() { await Assert.ThrowsAsync(() - => _teamsClient.GetOperationStateAsync(null!, _serviceUrl)); + => _teamsClient.GetOperationStateAsync(null!, _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task GetPagedFailedEntries_ThrowsOnNullOperationId() { await Assert.ThrowsAsync(() - => _teamsClient.GetPagedFailedEntriesAsync(null!, _serviceUrl)); + => _teamsClient.GetPagedFailedEntriesAsync(null!, _serviceUrl, null, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } [Fact] public async Task CancelOperation_ThrowsOnNullOperationId() { await Assert.ThrowsAsync(() - => _teamsClient.CancelOperationAsync(null!, _serviceUrl)); + => _teamsClient.CancelOperationAsync(null!, _serviceUrl, AgenticIdentitiyFromEnv.GetAgenticIdentity())); } #endregion From 57ea9b903f1fc152acd1d0f39d2da179466e6b62 Mon Sep 17 00:00:00 2001 From: "Ricardo Minguez Pablos (RIDO)" Date: Mon, 9 Feb 2026 17:01:09 -0800 Subject: [PATCH 4/5] remove skip permissions --- .../TeamsApiClientTests.cs | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs b/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs index 1e115287..828ab0b0 100644 --- a/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs +++ b/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs @@ -110,7 +110,7 @@ await Assert.ThrowsAsync(() #region Meeting Operations Tests - [Fact(Skip = "Batch operations require special permissions")] + [Fact] public async Task FetchMeetingInfo() { string meetingId = Environment.GetEnvironmentVariable("TEST_MEETINGID") ?? throw new InvalidOperationException("TEST_MEETINGID environment variable not set"); @@ -177,7 +177,7 @@ public async Task FetchParticipant() } } - [Fact(Skip = "Requires active meeting context")] + [Fact] public async Task SendMeetingNotification() { string meetingId = Environment.GetEnvironmentVariable("TEST_MEETINGID") ?? throw new InvalidOperationException("TEST_MEETINGID environment variable not set"); @@ -224,10 +224,10 @@ public async Task SendMeetingNotification() #region Batch Message Operations Tests - [Fact(Skip = "Batch operations require special permissions")] + [Fact] public async Task SendMessageToListOfUsers() { - string tenantId = Environment.GetEnvironmentVariable("TENANT_ID") ?? throw new InvalidOperationException("TENANT_ID environment variable not set"); + string tenantId = Environment.GetEnvironmentVariable("TEST_TENANTID") ?? throw new InvalidOperationException("TEST_TENANTID environment variable not set"); string userId = Environment.GetEnvironmentVariable("TEST_USER_ID") ?? throw new InvalidOperationException("TEST_USER_ID environment variable not set"); CoreActivity activity = new() @@ -238,6 +238,11 @@ public async Task SendMessageToListOfUsers() IList members = [ + new TeamMember(userId), + new TeamMember(userId), + new TeamMember(userId), + new TeamMember(userId), + new TeamMember(userId), new TeamMember(userId) ]; @@ -255,10 +260,10 @@ public async Task SendMessageToListOfUsers() testOutput.WriteLine($"Batch message sent. Operation ID: {operationId}"); } - [Fact(Skip = "Batch operations require special permissions")] + [Fact] public async Task SendMessageToAllUsersInTenant() { - string tenantId = Environment.GetEnvironmentVariable("TENANT_ID") ?? throw new InvalidOperationException("TENANT_ID environment variable not set"); + string tenantId = Environment.GetEnvironmentVariable("TEST_TENANTID") ?? throw new InvalidOperationException("TEST_TENANTID environment variable not set"); CoreActivity activity = new() { @@ -279,10 +284,10 @@ public async Task SendMessageToAllUsersInTenant() testOutput.WriteLine($"Tenant-wide message sent. Operation ID: {operationId}"); } - [Fact(Skip = "Batch operations require special permissions")] + [Fact] public async Task SendMessageToAllUsersInTeam() { - string tenantId = Environment.GetEnvironmentVariable("TENANT_ID") ?? throw new InvalidOperationException("TENANT_ID environment variable not set"); + string tenantId = Environment.GetEnvironmentVariable("TEST_TENANTID") ?? throw new InvalidOperationException("TEST_TENANTID environment variable not set"); string teamId = Environment.GetEnvironmentVariable("TEST_TEAMID") ?? throw new InvalidOperationException("TEST_TEAMID environment variable not set"); CoreActivity activity = new() @@ -340,10 +345,10 @@ public async Task SendMessageToListOfChannels() #region Batch Operation Management Tests - [Fact(Skip = "Requires valid operation ID from batch operation")] + [Fact] public async Task GetOperationState() { - string operationId = Environment.GetEnvironmentVariable("TEST_OPERATION_ID") ?? throw new InvalidOperationException("TEST_OPERATION_ID environment variable not set"); + string operationId = "amer_9d3424a5-6ce6-477f-934d-59e8ea5f7f27"; // Environment.GetEnvironmentVariable("TEST_OPERATION_ID") ?? throw new InvalidOperationException("TEST_OPERATION_ID environment variable not set"); BatchOperationState result = await _teamsClient.GetOperationStateAsync( operationId, From 26d7f0115c437bb15750fad665b958392c245484 Mon Sep 17 00:00:00 2001 From: "Ricardo Minguez Pablos (RIDO)" Date: Thu, 12 Feb 2026 17:43:12 -0800 Subject: [PATCH 5/5] Set Conversation.Id from env var in tenant message test Explicitly assign Conversation.Id in CoreActivity using the TEST_CONVERSATIONID environment variable, with error handling if not set. This ensures the test message is associated with the correct conversation context. --- .../Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs b/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs index 828ab0b0..24035ed7 100644 --- a/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs +++ b/core/test/Microsoft.Teams.Bot.Core.Tests/TeamsApiClientTests.cs @@ -268,7 +268,11 @@ public async Task SendMessageToAllUsersInTenant() CoreActivity activity = new() { Type = ActivityType.Message, - Properties = { { "text", $"Tenant-wide message from Automated tests at `{DateTime.UtcNow:s}`" } } + Properties = { { "text", $"Tenant-wide message from Automated tests at `{DateTime.UtcNow:s}`" } }, + Conversation = new() + { + Id = Environment.GetEnvironmentVariable("TEST_CONVERSATIONID") ?? throw new InvalidOperationException("TEST_ConversationId environment variable not set") + } }; string operationId = await _teamsClient.SendMessageToAllUsersInTenantAsync(