build-flow.api/tests/BuildFlow.Workflow.Tests/Handlers/AddSignerCommandHandlerTests.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

127 lines
4.4 KiB
C#

using BuildFlow.Shared.Domain.Errors;
using FluentAssertions;
using Microsoft.EntityFrameworkCore;
using Workflow.Application.Features.WorkflowTasks.Commands;
using Workflow.Application.Features.WorkflowTasks.Handlers;
using Workflow.Domain.Entities;
using Workflow.Domain.Enums;
using Xunit;
using TaskStatus = global::Workflow.Domain.Enums.TaskStatus;
namespace BuildFlow.Workflow.Tests.Handlers;
public class AddSignerCommandHandlerTests
{
private static WorkflowDbContext CreateDbContext()
{
var options = new DbContextOptionsBuilder<WorkflowDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
var db = new WorkflowDbContext(options);
db.SavingChanges += AuditStub.OnSave;
return db;
}
private static WorkflowTask SeedTask(WorkflowDbContext db, Guid assigneeId, TaskStatus status)
{
var task = new WorkflowTask
{
Id = Guid.NewGuid(),
InstanceId = Guid.NewGuid(),
TokenId = Guid.NewGuid(),
NodeId = Guid.NewGuid(),
Title = "Approve",
AssigneeId = assigneeId,
Status = status
};
db.WorkflowTasks.Add(task);
return task;
}
[Fact]
public async Task AddSigner_Before_DelegatesOriginalAndCreatesSignerTask()
{
await using var db = CreateDbContext();
var current = Guid.NewGuid();
var signer = Guid.NewGuid();
var task = SeedTask(db, current, TaskStatus.Pending);
await db.SaveChangesAsync();
var handler = new AddSignerCommandHandler(db);
var command = new AddSignerCommand(task.Id, current, signer, SignPosition.Before, null);
await handler.Handle(command, CancellationToken.None);
var stored = await db.WorkflowTasks.FindAsync(task.Id);
stored!.Status.Should().Be(TaskStatus.Delegated);
var signerTasks = await db.WorkflowTasks
.Where(t => t.AssigneeId == signer && t.Status == TaskStatus.Pending)
.ToListAsync();
signerTasks.Should().HaveCount(1);
}
[Fact]
public async Task AddSigner_MissingTask_ThrowsNotFound()
{
await using var db = CreateDbContext();
var handler = new AddSignerCommandHandler(db);
var command = new AddSignerCommand(Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), SignPosition.Before, 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 AddSigner_NonPendingTask_ThrowsInvalidState()
{
await using var db = CreateDbContext();
var task = SeedTask(db, Guid.NewGuid(), TaskStatus.Approved);
await db.SaveChangesAsync();
var handler = new AddSignerCommandHandler(db);
var command = new AddSignerCommand(task.Id, task.AssigneeId!.Value, Guid.NewGuid(), SignPosition.Before, null);
var act = async () => await handler.Handle(command, CancellationToken.None);
var ex = await act.Should().ThrowAsync<BusinessException>();
ex.Which.Code.Should().Be(ErrorCode.InvalidState);
}
[Fact]
public async Task AddSigner_NotCurrentHandler_ThrowsForbidden()
{
await using var db = CreateDbContext();
var task = SeedTask(db, Guid.NewGuid(), TaskStatus.Pending);
await db.SaveChangesAsync();
var handler = new AddSignerCommandHandler(db);
var command = new AddSignerCommand(task.Id, Guid.NewGuid(), Guid.NewGuid(), SignPosition.Before, null);
var act = async () => await handler.Handle(command, CancellationToken.None);
var ex = await act.Should().ThrowAsync<UnauthorizedException>();
ex.Which.Code.Should().Be(ErrorCode.Forbidden);
}
[Fact]
public async Task AddSigner_SelfSign_ThrowsBusiness()
{
await using var db = CreateDbContext();
var current = Guid.NewGuid();
var task = SeedTask(db, current, TaskStatus.Pending);
await db.SaveChangesAsync();
var handler = new AddSignerCommandHandler(db);
var command = new AddSignerCommand(task.Id, current, current, SignPosition.Before, null);
var act = async () => await handler.Handle(command, CancellationToken.None);
var ex = await act.Should().ThrowAsync<BusinessException>();
ex.Which.Code.Should().Be(ErrorCode.Business);
}
}