- 添加HNSW向量索引提升检索性能 - 实现Hybrid检索模式支持向量和关键词双路召回 - 采用RRF算法融合多路召回结果 - 支持ParentChild分块模式的上下文回填 - 优化向量写入采用批量SQL操作提升性能 - 添加RAG PostgreSQL连接字符串配置 - 更新部署脚本增加PGVector集成测试 - 修正表名引用从document_chunks到b_document_chunks - 重构RagRetrievalService实现完整的检索流程 - 增加重排策略支持关键词和LLM重排 - 修改服务器部署地址配置
115 lines
4.8 KiB
C#
115 lines
4.8 KiB
C#
using BuildFlow.Shared.Domain.Errors;
|
||
using BuildFlow.Shared.Domain.Exceptions;
|
||
using FluentAssertions;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using NSubstitute;
|
||
using Scripting.Application.Commands;
|
||
using Scripting.Application.DTOs;
|
||
using Scripting.Application.Handlers;
|
||
using Scripting.Application.Services;
|
||
using Scripting.Domain.Entities.ScriptFunction;
|
||
using Scripting.Domain.Enums;
|
||
using Scripting.Infrastructure.Persistence;
|
||
using Xunit;
|
||
|
||
namespace BuildFlow.Scripting.Tests;
|
||
|
||
/// <summary>
|
||
/// scripting 模块命令处理器测试(架构护栏:每个 Handler 至少 1 个测试)。
|
||
/// DisableScriptCommandHandler:真实 InMemory 覆盖成功置 Disabled 与不存在→NotFound。
|
||
/// TestScriptCommandHandler / InvokeScriptCommandHandler:仅委托 IScriptExecutionService,
|
||
/// 不触发真实 Roslyn 编译执行(依赖编译/沙箱执行,需集成环境),故用 NSubstitute 桩验证委托
|
||
/// 把请求正确转发给 ExecuteTestAsync / ExecuteByNameAsync 并返回其结果。
|
||
/// </summary>
|
||
public class ScriptCommandEdgeHandlerTests
|
||
{
|
||
// ── DisableScript ──────────────────────────────────────────────────────
|
||
|
||
[Fact]
|
||
public async Task DisableScript_Published_SetsDisabledAndPersists()
|
||
{
|
||
await using var db = ScriptingTestDbFactory.Create();
|
||
var script = await SeedScriptAsync(db, "disable-fn", ScriptStatusEnum.Published);
|
||
var handler = new DisableScriptCommandHandler(db);
|
||
|
||
var dto = await handler.Handle(new DisableScriptCommand(script.Id), CancellationToken.None);
|
||
|
||
dto.Status.Should().Be(ScriptStatusEnum.Disabled);
|
||
var entity = await db.Scripts.FindAsync(script.Id);
|
||
entity.Should().NotBeNull();
|
||
entity!.Status.Should().Be(ScriptStatusEnum.Disabled);
|
||
}
|
||
|
||
[Fact]
|
||
public async Task DisableScript_NotFound_Throws()
|
||
{
|
||
await using var db = ScriptingTestDbFactory.Create();
|
||
var handler = new DisableScriptCommandHandler(db);
|
||
|
||
var act = async () => await handler.Handle(
|
||
new DisableScriptCommand(Guid.NewGuid()), CancellationToken.None);
|
||
|
||
var ex = await act.Should().ThrowAsync<BusinessException>();
|
||
ex.Which.Code.Should().Be(ErrorCode.NotFound);
|
||
}
|
||
|
||
// ── TestScript(委托执行服务,前置分支无校验,仅验证委托) ───────────────
|
||
|
||
[Fact]
|
||
public async Task TestScript_DelegatesToService_ReturnsResult()
|
||
{
|
||
var svc = Substitute.For<IScriptExecutionService>();
|
||
var expected = new ScriptExecutionResult(ScriptExecutionStatusEnum.Success, "42", null, 7);
|
||
var req = new TestScriptCommand(Guid.NewGuid(), "{\"x\":1}");
|
||
svc.ExecuteTestAsync(req.Id, req.InputJson, Arg.Any<CancellationToken>()).Returns(expected);
|
||
var handler = new TestScriptCommandHandler(svc);
|
||
|
||
var result = await handler.Handle(req, CancellationToken.None);
|
||
|
||
result.Should().Be(expected);
|
||
await svc.Received(1).ExecuteTestAsync(req.Id, req.InputJson, Arg.Any<CancellationToken>());
|
||
}
|
||
|
||
// ── InvokeScript(委托执行服务,仅 Published 可调用由服务守卫) ──────────
|
||
|
||
[Fact]
|
||
public async Task InvokeScript_DelegatesToService_ReturnsResult()
|
||
{
|
||
var svc = Substitute.For<IScriptExecutionService>();
|
||
var expected = new ScriptExecutionResult(ScriptExecutionStatusEnum.Success, "99", null, 3);
|
||
var req = new InvokeScriptCommand("my-script", "{}");
|
||
svc.ExecuteByNameAsync(req.Name, req.InputJson, Arg.Any<CancellationToken>()).Returns(expected);
|
||
var handler = new InvokeScriptCommandHandler(svc);
|
||
|
||
var result = await handler.Handle(req, CancellationToken.None);
|
||
|
||
result.Should().Be(expected);
|
||
await svc.Received(1).ExecuteByNameAsync(req.Name, req.InputJson, Arg.Any<CancellationToken>());
|
||
}
|
||
|
||
// ── 夹具 ───────────────────────────────────────────────────────────────
|
||
|
||
private static async Task<ScriptFunctionEntity> SeedScriptAsync(
|
||
ScriptingDbContext db,
|
||
string name,
|
||
ScriptStatusEnum status = ScriptStatusEnum.Draft)
|
||
{
|
||
var script = new ScriptFunctionEntity
|
||
{
|
||
Id = Guid.NewGuid(),
|
||
Name = name,
|
||
DisplayName = name,
|
||
Code = "return 1;",
|
||
Status = status,
|
||
Version = 1,
|
||
TimeoutMs = 5000,
|
||
CreatedBy = "test",
|
||
UpdatedBy = "test",
|
||
OperatorIP = "127.0.0.1",
|
||
};
|
||
db.Scripts.Add(script);
|
||
await db.SaveChangesAsync();
|
||
return script;
|
||
}
|
||
}
|