diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/MockAgentProvider.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/MockAgentProvider.cs index 8a2e76415a..22438e2c6e 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/MockAgentProvider.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/MockAgentProvider.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.AI; @@ -16,18 +17,29 @@ internal sealed class MockAgentProvider : Mock { public IList ExistingConversationIds { get; } = []; - public ChatMessage? TestChatMessage { get; set; } + public List? TestMessages { get; set; } public MockAgentProvider() { this.Setup(provider => provider.CreateConversationAsync(It.IsAny())) .Returns(() => Task.FromResult(this.CreateConversationId())); + List testMessages = this.CreateMessages(); this.Setup(provider => provider.GetMessageAsync( It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(Task.FromResult(this.CreateChatMessage())); + .Returns(Task.FromResult(testMessages.First())); + + // Setup GetMessagesAsync to return test messages + this.Setup(provider => provider.GetMessagesAsync( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(ToAsyncEnumerableAsync(testMessages)); } private string CreateConversationId() @@ -38,12 +50,27 @@ private string CreateConversationId() return newConversationId; } - private ChatMessage CreateChatMessage() + private List CreateMessages() { - this.TestChatMessage = new ChatMessage(ChatRole.User, Guid.NewGuid().ToString("N")) + // Create test messages + List messages = []; + const int MessageCount = 5; + for (int i = 0; i < MessageCount; i++) { - MessageId = Guid.NewGuid().ToString("N"), - }; - return this.TestChatMessage; + messages.Add(new ChatMessage(ChatRole.User, $"Test message {i + 1}") { MessageId = Guid.NewGuid().ToString("N") }); + } + this.TestMessages = messages; + + return this.TestMessages; + } + + private static async IAsyncEnumerable ToAsyncEnumerableAsync(IEnumerable messages) + { + foreach (ChatMessage message in messages) + { + yield return message; + } + + await Task.CompletedTask; } } diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/ObjectModel/RetrieveConversationMessageExecutorTest.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/ObjectModel/RetrieveConversationMessageExecutorTest.cs index 3f9fa0d606..04fcd81a3c 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/ObjectModel/RetrieveConversationMessageExecutorTest.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/ObjectModel/RetrieveConversationMessageExecutorTest.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. +using System.Linq; using System.Threading.Tasks; using Microsoft.Agents.AI.Workflows.Declarative.Extensions; using Microsoft.Agents.AI.Workflows.Declarative.ObjectModel; @@ -41,7 +42,8 @@ private async Task ExecuteTestAsync( await this.ExecuteAsync(action); // Assert - ChatMessage testMessage = mockAgentProvider.TestChatMessage ?? new ChatMessage(); + ChatMessage? testMessage = mockAgentProvider.TestMessages?.FirstOrDefault(); + Assert.NotNull(testMessage); VerifyModel(model, action); this.VerifyState(variableName, testMessage.ToRecord()); } diff --git a/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/ObjectModel/RetrieveConversationMessagesExecutorTest.cs b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/ObjectModel/RetrieveConversationMessagesExecutorTest.cs new file mode 100644 index 0000000000..6c287a911b --- /dev/null +++ b/dotnet/tests/Microsoft.Agents.AI.Workflows.Declarative.UnitTests/ObjectModel/RetrieveConversationMessagesExecutorTest.cs @@ -0,0 +1,113 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System.Threading.Tasks; +using Microsoft.Agents.AI.Workflows.Declarative.Extensions; +using Microsoft.Agents.AI.Workflows.Declarative.ObjectModel; +using Microsoft.Bot.ObjectModel; +using Xunit.Abstractions; + +namespace Microsoft.Agents.AI.Workflows.Declarative.UnitTests.ObjectModel; + +/// +/// Tests for . +/// +public sealed class RetrieveConversationMessagesExecutorTest(ITestOutputHelper output) : WorkflowActionExecutorTest(output) +{ + [Fact] + public async Task RetrieveAllMessagesSuccessfullyAsync() + { + // Arrange, Act, Assert + await this.ExecuteTestAsync( + nameof(RetrieveAllMessagesSuccessfullyAsync), + "TestMessages", + "TestConversationId"); + } + + [Fact] + public async Task RetrieveMessagesWithOptionalValuesAsync() + { + // Arrange, Act, Assert + await this.ExecuteTestAsync( + nameof(RetrieveMessagesWithOptionalValuesAsync), + "TestMessages", + "TestConversationId", + limit: IntExpression.Literal(2), + after: StringExpression.Literal("11/01/2025"), + before: StringExpression.Literal("12/01/2025"), + sortOrder: EnumExpression.Literal(AgentMessageSortOrderWrapper.Get(AgentMessageSortOrder.NewestFirst))); + } + + private async Task ExecuteTestAsync( + string displayName, + string variableName, + string conversationId, + IntExpression? limit = null, + StringExpression? after = null, + StringExpression? before = null, + EnumExpression? sortOrder = null) + { + // Arrange + MockAgentProvider mockAgentProvider = new(); + + RetrieveConversationMessages model = this.CreateModel( + this.FormatDisplayName(displayName), + FormatVariablePath(variableName), + conversationId, + limit, + after, + before, + sortOrder); + + RetrieveConversationMessagesExecutor action = new(model, mockAgentProvider.Object, this.State); + + // Act + await this.ExecuteAsync(action); + + // Assert + var testMessages = mockAgentProvider.TestMessages; + Assert.NotNull(testMessages); + VerifyModel(model, action); + this.VerifyState(variableName, testMessages.ToTable()); + } + + private RetrieveConversationMessages CreateModel( + string displayName, + string variableName, + string conversationId, + IntExpression? limit, + StringExpression? after, + StringExpression? before, + EnumExpression? sortOrder) + { + RetrieveConversationMessages.Builder actionBuilder = + new() + { + Id = this.CreateActionId(), + DisplayName = this.FormatDisplayName(displayName), + Messages = PropertyPath.Create(variableName), + ConversationId = StringExpression.Literal(conversationId) + }; + + if (limit is not null) + { + actionBuilder.Limit = limit; + } + + if (after is not null) + { + actionBuilder.MessageAfter = after; + } + + if (before is not null) + { + actionBuilder.MessageBefore = before; + } + + if (sortOrder is not null) + { + actionBuilder.SortOrder = sortOrder; + } + + return AssignParent(actionBuilder); + } +}