121 lines
5.1 KiB
C#
Raw Normal View History

// Copyright (c) Microsoft Corporation. All rights reserved.
// SendMessageTests.cs
using System.Diagnostics;
using System.Reflection;
using FluentAssertions;
using Microsoft.AutoGen.Contracts;
using Microsoft.Extensions.Logging;
using Xunit;
namespace Microsoft.AutoGen.Core.Tests;
[Trait("Category", "UnitV2")]
public partial class SendMessageTests
{
private sealed class SendOnAgent : BaseAgent, IHandle<BasicMessage>
{
private IList<Guid> targetKeys;
public SendOnAgent(AgentId id, IAgentRuntime runtime, string description, IList<Guid> targetKeys, ILogger<BaseAgent>? logger = null)
: base(id, runtime, description, logger)
{
this.targetKeys = targetKeys;
}
public async ValueTask HandleAsync(BasicMessage item, MessageContext messageContext)
{
foreach (Guid targetKey in targetKeys)
{
AgentId targetId = new(nameof(ReceiverAgent), targetKey.ToString());
BasicMessage message = new BasicMessage { Content = $"@{targetKey}: {item.Content}" };
await this.Runtime.SendMessageAsync(message, targetId);
}
}
}
[Fact]
public async Task Test_SendMessage_ReturnsValue()
{
Func<string, string> ProcessFunc = (s) => $"Processed({s})";
MessagingTestFixture fixture = new MessagingTestFixture();
await fixture.RegisterFactoryMapInstances(nameof(ProcessorAgent),
(id, runtime) => ValueTask.FromResult(new ProcessorAgent(id, runtime, ProcessFunc, string.Empty)));
AgentId targetAgent = new AgentId(nameof(ProcessorAgent), Guid.NewGuid().ToString());
object? maybeResult = await fixture.RunSendTestAsync(targetAgent, new BasicMessage { Content = "1" });
maybeResult.Should().NotBeNull()
.And.BeOfType<BasicMessage>()
.And.Match<BasicMessage>(m => m.Content == "Processed(1)");
}
[Fact]
public async Task Test_SendMessage_Cancellation()
{
MessagingTestFixture fixture = new MessagingTestFixture();
await fixture.RegisterFactoryMapInstances(nameof(CancelAgent),
(id, runtime) => ValueTask.FromResult(new CancelAgent(id, runtime, string.Empty)));
AgentId targetAgent = new AgentId(nameof(CancelAgent), Guid.NewGuid().ToString());
Func<Task> testAction = () => fixture.RunSendTestAsync(targetAgent, new BasicMessage { Content = "1" }).AsTask();
// TODO: Do we want to do the unwrap in this case?
await testAction.Should().ThrowAsync<OperationCanceledException>();
}
[Fact]
public async Task Test_SendMessage_Error()
{
MessagingTestFixture fixture = new MessagingTestFixture();
await fixture.RegisterFactoryMapInstances(nameof(ErrorAgent),
(id, runtime) => ValueTask.FromResult(new ErrorAgent(id, runtime, string.Empty)));
AgentId targetAgent = new AgentId(nameof(ErrorAgent), Guid.NewGuid().ToString());
Func<Task> testAction = () => fixture.RunSendTestAsync(targetAgent, new BasicMessage { Content = "1" }).AsTask();
(await testAction.Should().ThrowAsync<TargetInvocationException>())
.WithInnerException<TestException>();
}
[Fact]
public async Task TesT_SendMessage_FromSendMessageHandler()
{
Guid[] targetGuids = [Guid.NewGuid(), Guid.NewGuid()];
MessagingTestFixture fixture = new MessagingTestFixture();
Dictionary<AgentId, SendOnAgent> sendAgents = fixture.GetAgentInstances<SendOnAgent>();
Dictionary<AgentId, ReceiverAgent> receiverAgents = fixture.GetAgentInstances<ReceiverAgent>();
await fixture.RegisterFactoryMapInstances(nameof(SendOnAgent),
(id, runtime) => ValueTask.FromResult(new SendOnAgent(id, runtime, string.Empty, targetGuids)));
await fixture.RegisterFactoryMapInstances(nameof(ReceiverAgent),
(id, runtime) => ValueTask.FromResult(new ReceiverAgent(id, runtime, string.Empty)));
const string HelloContent = "Hello";
AgentId targetAgent = new AgentId(nameof(SendOnAgent), Guid.NewGuid().ToString());
Task testTask = fixture.RunSendTestAsync(targetAgent, new BasicMessage { Content = HelloContent }).AsTask();
// We do not actually expect to wait the timeout here, but it is still better than waiting the 10 min
// timeout that the tests default to. A failure will fail regardless of what timeout value we set.
TimeSpan timeout = Debugger.IsAttached ? TimeSpan.FromSeconds(120) : TimeSpan.FromSeconds(10);
Task timeoutTask = Task.Delay(timeout);
Task completedTask = await Task.WhenAny([testTask, timeoutTask]);
completedTask.Should().Be(testTask, "SendOnAgent should complete before timeout");
// Check that each of the target agents received the message
foreach (var targetKey in targetGuids)
{
var targetId = new AgentId(nameof(ReceiverAgent), targetKey.ToString());
receiverAgents[targetId].Messages.Should().ContainSingle(m => m.Content == $"@{targetKey}: {HelloContent}");
}
}
}