- 将菜单实体的 ID 类型从 Guid 改为 long,并配置为自增主键 - 添加菜单创建、删除、树形结构构建等完整的 CRUD 操作支持 - 为文件上传相关端点添加 file:upload 权限验证 - 为文件操作端点添加 file:read 和 file:write 权限控制 - 为通知功能添加 notification:read 权限限制 - 实现 BuildFlow 按钮执行的权限检查机制 - 在 IM 模块中集成 Redis 未读计数器优化性能 - 更新用户主页路径从 /workspace 到 /dashboard/workspace - 添加 SignalR Hub 授权和 WebSocket 连接安全保护 - 新增平台测试项目并完善按钮权限测试用例
58 lines
2.1 KiB
C#
58 lines
2.1 KiB
C#
using IM.Application.Chat.Handlers;
|
||
using IM.Application.Chat.Queries;
|
||
using IM.Domain.Common;
|
||
using IM.Domain.Enums;
|
||
using IM.Infrastructure.Persistence;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
using Moq;
|
||
using Xunit;
|
||
|
||
namespace BuildFlow.IM.Tests.Chat;
|
||
|
||
/// <summary>
|
||
/// GetUnreadCountQueryHandler 的读扩散断言:Redis 命中必须能独立驱动未读汇总。
|
||
/// </summary>
|
||
public class GetUnreadCountQueryHandlerTests
|
||
{
|
||
private static readonly Guid UserId = Guid.Parse("22222222-2222-2222-2222-222222222222");
|
||
private static readonly Guid OtherUserId = Guid.Parse("33333333-3333-3333-3333-333333333333");
|
||
private static readonly Guid ConversationId = Guid.Parse("11111111-1111-1111-1111-111111111111");
|
||
|
||
[Fact]
|
||
public async Task Returns_redis_unread_even_when_pg_cold_backup_is_zero()
|
||
{
|
||
await using var db = BuildInMemoryDb();
|
||
db.Conversations.Add(ImTestData.BuildConversation(
|
||
ConversationId,
|
||
ConversationType.Private,
|
||
(UserId, 0),
|
||
(OtherUserId, 0)));
|
||
await db.SaveChangesAsync();
|
||
|
||
var unreadCounter = new Mock<IUnreadCounter>();
|
||
unreadCounter
|
||
.Setup(c => c.GetByUserAsync(
|
||
UserId,
|
||
It.Is<IEnumerable<Guid>>(ids => ids.SequenceEqual(new[] { ConversationId })),
|
||
It.IsAny<CancellationToken>()))
|
||
.ReturnsAsync(new Dictionary<Guid, int> { [ConversationId] = 3 });
|
||
|
||
var handler = new GetUnreadCountQueryHandler(db, unreadCounter.Object);
|
||
|
||
var result = await handler.Handle(new GetUnreadCountQuery(UserId), CancellationToken.None);
|
||
|
||
Assert.Equal(3, result.Total);
|
||
var item = Assert.Single(result.Items);
|
||
Assert.Equal(ConversationId, item.ConversationId);
|
||
Assert.Equal(3, item.UnreadCount);
|
||
}
|
||
|
||
private static ImDbContext BuildInMemoryDb()
|
||
{
|
||
var services = new ServiceCollection();
|
||
services.AddDbContext<ImDbContext>(o => o.UseInMemoryDatabase($"im-unread-{Guid.NewGuid()}"));
|
||
return services.BuildServiceProvider().GetRequiredService<ImDbContext>();
|
||
}
|
||
}
|