- 将通用 Entities 命名空间拆分为具体业务实体子目录 - 更新所有实体类型引用为具体的 Entity 后缀类型 - 将 ModelType、ModelProvider、GroupMemberRole 等枚举重命名为 Enum 后缀 - 重构 AiModel 相关配置和映射逻辑适配新的实体结构 - 更新测试代码中的实体类型引用和枚举使用 - 调整应用层处理器中的实体创建和查询逻辑 - 修改 appsettings.json 中的基础设施主机配置为动态占位符模式
96 lines
3.6 KiB
C#
96 lines
3.6 KiB
C#
using IM.Domain.Entities.Conversation;
|
||
using IM.Domain.Entities.ConversationParticipant;
|
||
using IM.Domain.Entities.Group;
|
||
using IM.Domain.Entities.GroupMember;
|
||
using IM.Domain.Enums;
|
||
using IM.Infrastructure.Persistence;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.DependencyInjection;
|
||
|
||
namespace BuildFlow.IM.Integration.Tests;
|
||
|
||
/// <summary>
|
||
/// 集成测试数据播种助手。直接写真实 PostgreSQL,构造会话/群组/群成员,
|
||
/// 供 ChatHub 与 MediatR handler 读写。
|
||
/// </summary>
|
||
public static class ImTestSeeder
|
||
{
|
||
/// <summary>
|
||
/// 播种一个私聊会话(两参与者),返回会话 ID。
|
||
/// </summary>
|
||
public static async Task<Guid> SeedPrivateConversationAsync(ImServerFixture fixture, Guid userA, Guid userB)
|
||
{
|
||
await using var scope = fixture.Services.CreateAsyncScope();
|
||
var db = scope.ServiceProvider.GetRequiredService<ImDbContext>();
|
||
|
||
var conv = new ConversationEntity { Type = ConversationTypeEnum.Private };
|
||
conv.Participants =
|
||
[
|
||
new ConversationParticipantEntity { ConversationId = conv.Id, UserId = userA, JoinedAt = DateTime.UtcNow },
|
||
new ConversationParticipantEntity { ConversationId = conv.Id, UserId = userB, JoinedAt = DateTime.UtcNow },
|
||
];
|
||
db.Conversations.Add(conv);
|
||
await db.SaveChangesAsync();
|
||
return conv.Id;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 播种一个群聊会话:创建会话 + 群组 + 群成员,返回(会话ID, 群ID)。
|
||
/// <paramref name="members"/> 形如 (userId, role) 列表,决定每个成员的群角色(影响撤回权限)。
|
||
/// </summary>
|
||
public static async Task<(Guid ConversationId, Guid GroupId)> SeedGroupConversationAsync(
|
||
ImServerFixture fixture,
|
||
string groupName,
|
||
Guid ownerId,
|
||
params (Guid UserId, GroupMemberRoleEnum Role)[] members)
|
||
{
|
||
await using var scope = fixture.Services.CreateAsyncScope();
|
||
var db = scope.ServiceProvider.GetRequiredService<ImDbContext>();
|
||
|
||
var conv = new ConversationEntity { Type = ConversationTypeEnum.Group };
|
||
var group = new GroupEntity
|
||
{
|
||
ConversationId = conv.Id,
|
||
Name = groupName,
|
||
OwnerId = ownerId,
|
||
};
|
||
|
||
// 群成员同时是会话参与者(决定谁能收发消息)
|
||
foreach (var (userId, _) in members)
|
||
{
|
||
conv.Participants.Add(new ConversationParticipantEntity
|
||
{
|
||
ConversationId = conv.Id,
|
||
UserId = userId,
|
||
JoinedAt = DateTime.UtcNow,
|
||
});
|
||
}
|
||
foreach (var (userId, role) in members)
|
||
{
|
||
group.Members.Add(new GroupMemberEntity
|
||
{
|
||
GroupId = group.Id,
|
||
UserId = userId,
|
||
Role = role,
|
||
JoinedAt = DateTime.UtcNow,
|
||
});
|
||
}
|
||
|
||
db.Conversations.Add(conv);
|
||
db.Groups.Add(group);
|
||
await db.SaveChangesAsync();
|
||
return (conv.Id, group.Id);
|
||
}
|
||
|
||
/// <summary>读取某用户在某会话的 PG 未读数(冷备读路径,验证双写一致性)。</summary>
|
||
public static async Task<int> GetPgUnreadAsync(ImServerFixture fixture, Guid conversationId, Guid userId)
|
||
{
|
||
await using var scope = fixture.Services.CreateAsyncScope();
|
||
var db = scope.ServiceProvider.GetRequiredService<ImDbContext>();
|
||
var p = await db.ConversationParticipants
|
||
.AsNoTracking()
|
||
.FirstAsync(p => p.ConversationId == conversationId && p.UserId == userId);
|
||
return p.UnreadCount;
|
||
}
|
||
}
|