Files
MyAgent/tests/MyAgent.Tests/Core/SessionManagerTests.cs
T

92 lines
3.2 KiB
C#

using Microsoft.Extensions.Options;
using MyAgent.Core;
using Xunit;
namespace MyAgent.Tests.Core;
public sealed class SessionManagerTests
{
[Fact]
public async Task DebounceAsync_TwoRapidMessagesProduceOneStableBatch()
{
var manager = CreateManager();
var now = DateTimeOffset.Now;
var first = manager.DebounceAsync(CreateMessage("1", "第一条", now));
await Task.Delay(10);
var second = manager.DebounceAsync(CreateMessage("2", "第二条", now.AddMilliseconds(10)));
Assert.Null(await first);
var batch = await second;
Assert.NotNull(batch);
Assert.Equal(2, batch!.Messages.Count);
Assert.Contains("第一条", batch.MergedText);
Assert.Contains("第二条", batch.MergedText);
}
[Fact]
public async Task DebounceAsync_CompletedBatchIsConsumed()
{
var manager = CreateManager();
var first = await manager.DebounceAsync(CreateMessage("1", "第一轮", DateTimeOffset.Now));
var second = await manager.DebounceAsync(CreateMessage("2", "第二轮", DateTimeOffset.Now.AddSeconds(1)));
Assert.Single(first!.Messages);
Assert.Single(second!.Messages);
Assert.Equal("第二轮", second.MergedText);
}
[Fact]
public async Task DebounceAsync_CallerCancellationDoesNotLeaveBrokenPendingState()
{
var manager = CreateManager();
using var cancellation = new CancellationTokenSource();
var cancelled = manager.DebounceAsync(CreateMessage("1", "取消", DateTimeOffset.Now), cancellation.Token);
cancellation.Cancel();
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => cancelled);
var next = await manager.DebounceAsync(CreateMessage("2", "下一条", DateTimeOffset.Now.AddSeconds(1)));
Assert.NotNull(next);
Assert.Single(next!.Messages);
}
[Fact]
public async Task DebounceAsync_DifferentUsersReplyingToSameMessageStayIsolated()
{
var manager = CreateManager();
var firstMessage = CreateMessage("1", "用户一", DateTimeOffset.Now, "1", "root");
var secondMessage = CreateMessage("2", "用户二", DateTimeOffset.Now, "2", "root");
var first = manager.DebounceAsync(firstMessage);
var second = manager.DebounceAsync(secondMessage);
var batches = await Task.WhenAll(first, second);
Assert.All(batches, batch => Assert.Single(batch!.Messages));
Assert.NotEqual(batches[0]!.ThreadId, batches[1]!.ThreadId);
}
private static SessionManager CreateManager()
{
var options = Options.Create(new ShirobotOptions
{
Fusion = new FusionOptions
{
DebounceMs = 40,
SameUserMergeWindowSec = 8,
MaxMergedMessages = 8
}
});
return new SessionManager(options, TimeProvider.System);
}
private static IncomingMessage CreateMessage(string id, string text, DateTimeOffset at, string userId = "1", string? replyToMessageId = null) => new()
{
MessageId = id,
GroupId = "1",
UserId = userId,
Text = text,
CreatedAt = at,
ReplyToMessageId = replyToMessageId
};
}