build-flow.api/tests/BuildFlow.Rag.Tests/UpdateAiModelCommandHandlerTests.cs
xiangning 7479521546 feat(rag): 实现RAG模块的Hybrid检索和向量索引优化
- 添加HNSW向量索引提升检索性能
- 实现Hybrid检索模式支持向量和关键词双路召回
- 采用RRF算法融合多路召回结果
- 支持ParentChild分块模式的上下文回填
- 优化向量写入采用批量SQL操作提升性能
- 添加RAG PostgreSQL连接字符串配置
- 更新部署脚本增加PGVector集成测试
- 修正表名引用从document_chunks到b_document_chunks
- 重构RagRetrievalService实现完整的检索流程
- 增加重排策略支持关键词和LLM重排
- 修改服务器部署地址配置
2026-08-11 10:59:09 +08:00

137 lines
4.2 KiB
C#

using BuildFlow.Application.AiModel.Commands;
using BuildFlow.Application.AiModel.Handlers;
using BuildFlow.Domain.Entities.AiModel;
using BuildFlow.Domain.Enums;
using BuildFlow.Infrastructure.Persistence;
using BuildFlow.Shared.Domain.Errors;
using BuildFlow.Shared.Domain.Exceptions;
using FluentAssertions;
using Microsoft.EntityFrameworkCore;
using Xunit;
namespace BuildFlow.Rag.Tests;
/// <summary>
/// 更新 AI 模型处理器测试。成功路径 + 不存在/参数校验异常分支。
/// </summary>
public class UpdateAiModelCommandHandlerTests
{
[Fact]
public async Task Handle_ExistingModel_UpdatesFields()
{
await using var db = CreateDb();
var modelId = Guid.NewGuid();
db.AiModels.Add(new AiModelEntity
{
Id = modelId,
Name = "Qwen",
Provider = ModelProviderEnum.LMStudio,
ModelId = "qwen2.5",
BaseUrl = "http://localhost:1234/v1",
ApiKey = "lm-studio",
ModelType = ModelTypeEnum.Chat,
IsActive = true,
CreatedBy = "test",
UpdatedBy = "test",
OperatorIP = "127.0.0.1",
});
await db.SaveChangesAsync();
var handler = new UpdateAiModelCommandHandler(db);
var command = new UpdateAiModelCommand(
modelId,
"Qwen-Updated",
(int)ModelProviderEnum.OpenAI,
"qwen3",
"https://api.openai.com/v1",
null,
(int)ModelTypeEnum.Chat,
false,
null,
null,
"系统提示词");
var result = await handler.Handle(command, CancellationToken.None);
result.Name.Should().Be("Qwen-Updated");
result.ModelId.Should().Be("qwen3");
result.IsActive.Should().BeFalse();
var persisted = await db.AiModels.FindAsync(modelId);
persisted!.Name.Should().Be("Qwen-Updated"); // 前面已断言存在
// ApiKey 传 null 时保留原值
persisted.ApiKey.Should().Be("lm-studio");
}
[Fact]
public async Task Handle_NotFound_ThrowsNotFound()
{
await using var db = CreateDb();
var handler = new UpdateAiModelCommandHandler(db);
var command = new UpdateAiModelCommand(
Guid.NewGuid(),
"Qwen",
(int)ModelProviderEnum.OpenAI,
"qwen3",
"https://api.openai.com/v1",
null,
(int)ModelTypeEnum.Chat,
false,
null,
null,
null);
var act = async () => await handler.Handle(command, CancellationToken.None);
var ex = await act.Should().ThrowAsync<NotFoundException>();
ex.Which.Code.Should().Be(ErrorCode.NotFound);
}
[Fact]
public async Task Handle_InvalidProvider_ThrowsInvalidParam()
{
await using var db = CreateDb();
var modelId = Guid.NewGuid();
db.AiModels.Add(new AiModelEntity
{
Id = modelId,
Name = "Qwen",
Provider = ModelProviderEnum.LMStudio,
ModelId = "qwen2.5",
BaseUrl = "http://localhost:1234/v1",
ApiKey = "lm-studio",
ModelType = ModelTypeEnum.Chat,
CreatedBy = "test",
UpdatedBy = "test",
OperatorIP = "127.0.0.1",
});
await db.SaveChangesAsync();
var handler = new UpdateAiModelCommandHandler(db);
var command = new UpdateAiModelCommand(
modelId,
"Qwen",
999,
"qwen3",
"https://api.openai.com/v1",
null,
(int)ModelTypeEnum.Chat,
false,
null,
null,
null);
var act = async () => await handler.Handle(command, CancellationToken.None);
var ex = await act.Should().ThrowAsync<BusinessException>();
ex.Which.Code.Should().Be(ErrorCode.InvalidParam);
}
private static RagDbContext CreateDb()
{
var options = new DbContextOptionsBuilder<RagDbContext>()
.UseInMemoryDatabase($"rag-update-aimodel-{Guid.NewGuid():N}")
.Options;
var db = new RagDbContext(options);
db.SavingChanges += (_, _) => RagTestDb.FillAudit(db);
return db;
}
}