xiangning a978e7f868 feat(workflow): 添加自定义函数类型和按钮三阶段动作链功能
- 引入 CustomFunctionType 枚举,支持 Script 和 Http 两种函数类型
- 在自定义函数中添加 Http 相关字段(HttpMethod、HttpUrl、HttpHeaders、HttpBodyTemplate)
- 实现 HTTP 函数执行器,支持变量替换和 SSRF 防护
- 将按钮动作链拆分为 before、main、after 三个阶段
- 新增前置和后置动作 JSON 字段存储
- 实现批量执行多个函数的 executeFunctions 动作类型
- 更新数据库迁移以支持新的字段结构
- 调整相关 DTO、命令和处理器以兼容新功能
2026-07-06 18:03:22 +08:00

84 lines
3.0 KiB
C#

using FluentAssertions;
using Workflow.Application.BuildFlow.CustomFunctions.Commands;
using Workflow.Application.BuildFlow.CustomFunctions.Handlers;
using Workflow.Application.BuildFlow.CustomFunctions.Services;
using Workflow.Domain.Enums;
using Xunit;
namespace BuildFlow.Workflow.Tests.BuildFlow;
/// <summary>
/// 自定义函数测试,约束函数必须发布后才能被运行,禁用后立即阻断。
/// </summary>
public class CustomFunctionTests
{
[Fact]
public async Task ExecuteAsync_PublishedFunction_ReturnsScriptResult()
{
await using var db = TestDbFactory.Create();
var createHandler = new CreateCustomFunctionCommandHandler(db);
var publishHandler = new PublishCustomFunctionCommandHandler(db);
var executor = new CustomFunctionExecutionService(db);
var function = await createHandler.Handle(
new CreateCustomFunctionCommand(
"amount-level",
"金额分级",
"按金额输出审批等级",
CustomFunctionType.Script,
"((System.Text.Json.JsonElement)Variables[\"amount\"]).GetDecimal() > 1000 ? \"high\" : \"normal\"",
null,
null,
null,
null,
"""{"type":"object"}""",
"""{"type":"string"}""",
5000),
CancellationToken.None);
await publishHandler.Handle(new PublishCustomFunctionCommand(function.Id), CancellationToken.None);
var result = await executor.ExecuteAsync(
function.Id,
"""{"amount":1200}""",
CancellationToken.None);
result.Status.Should().Be(CustomFunctionExecutionStatus.Success);
result.ResultJson.Should().Be("\"high\"");
}
[Fact]
public async Task ExecuteAsync_DisabledFunction_ThrowsBusinessException()
{
await using var db = TestDbFactory.Create();
var createHandler = new CreateCustomFunctionCommandHandler(db);
var publishHandler = new PublishCustomFunctionCommandHandler(db);
var disableHandler = new DisableCustomFunctionCommandHandler(db);
var executor = new CustomFunctionExecutionService(db);
var function = await createHandler.Handle(
new CreateCustomFunctionCommand(
"disabled-func",
"禁用函数",
null,
CustomFunctionType.Script,
""""ok"""",
null,
null,
null,
null,
null,
null,
5000),
CancellationToken.None);
await publishHandler.Handle(new PublishCustomFunctionCommand(function.Id), CancellationToken.None);
await disableHandler.Handle(new DisableCustomFunctionCommand(function.Id), CancellationToken.None);
var act = () => executor.ExecuteAsync(function.Id, "{}", CancellationToken.None);
await act.Should().ThrowAsync<BusinessException>()
.WithMessage("*已禁用*");
}
}