310 lines
9.3 KiB
Go
310 lines
9.3 KiB
Go
package tests
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"git.fsdpf.net/go/condflow"
|
|
"git.fsdpf.net/go/condflow/tests/fixtures"
|
|
"git.fsdpf.net/go/condition"
|
|
"git.fsdpf.net/go/contracts/base"
|
|
"git.fsdpf.net/go/reflux"
|
|
"git.fsdpf.net/go/reflux/fieldx"
|
|
"git.fsdpf.net/go/req"
|
|
"git.fsdpf.net/go/req/resx"
|
|
"github.com/samber/do/v2"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
// CondFlowTestSuite 条件流测试套件
|
|
type CondFlowTestSuite struct {
|
|
suite.Suite
|
|
app do.Injector
|
|
flow *condflow.CondFlow
|
|
executor condflow.ActionInvoker
|
|
}
|
|
|
|
// SetupTest 在每个测试前运行
|
|
func (s *CondFlowTestSuite) SetupTest() {
|
|
// 初始化 DI 容器
|
|
s.app = do.New()
|
|
|
|
// 创建 executor
|
|
approveRes := resx.New(s.app, "Approval", "approvals",
|
|
resx.WithUuid("550e8400-e29b-41d4-a716-446655440001"),
|
|
resx.WithName("审批"),
|
|
resx.WithFields(
|
|
resx.NewResField("id", "", resx.FieldWithName("ID"), resx.FieldWithDataType(req.ResInteger)),
|
|
resx.NewResField("created_user", "", resx.FieldWithName("创建者"), resx.FieldWithDefault("00000000-0000-0000-0000-000000000000"), resx.FieldWithDataType(req.ResString)),
|
|
resx.NewResField("owned_user", "", resx.FieldWithName("拥有者"), resx.FieldWithDefault("00000000-0000-0000-0000-000000000000"), resx.FieldWithDataType(req.ResString)),
|
|
resx.NewResField("created_at", "", resx.FieldWithName("创建时间"), resx.FieldWithDefault("sql:CURRENT_TIMESTAMP"), resx.FieldWithDataType(req.ResTimestamp)),
|
|
resx.NewResField("updated_at", "", resx.FieldWithName("更新时间"), resx.FieldWithDefault("sql:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"), resx.FieldWithDataType(req.ResTimestamp)),
|
|
resx.NewResField("uuid", "", resx.FieldWithName("UUID"), resx.FieldWithDefault("sql:uuid()"), resx.FieldWithDataType(req.ResString)),
|
|
resx.NewResField("status", "", resx.FieldWithName("状态"), resx.FieldWithDefault("pending"), resx.FieldWithDataType(req.ResString)),
|
|
resx.NewResField("amount", "", resx.FieldWithName("审批金额"), resx.FieldWithDefault("0"), resx.FieldWithDataType(req.ResDecimal)),
|
|
resx.NewResField("approver_role", "", resx.FieldWithName("审批人角色"), resx.FieldWithDataType(req.ResString)),
|
|
resx.NewResField("approval_method", "", resx.FieldWithName("审批方式"), resx.FieldWithDataType(req.ResString)),
|
|
),
|
|
)
|
|
|
|
s.executor = condflow.NewActionInvoker(fixtures.NewApproveExecutor(approveRes), nil)
|
|
|
|
do.ProvideNamedValue(s.app, fmt.Sprintf("%s/ApproveExecutor", s.executor.Res().GetCode()), s.executor)
|
|
|
|
// 通过字符串验证预期的 action 是否注册成功
|
|
expectedActions := []string{
|
|
"AutoApprove",
|
|
"Manager",
|
|
"Director",
|
|
"Reject",
|
|
}
|
|
|
|
for _, actionName := range expectedActions {
|
|
_, err := s.executor.GetAction(actionName)
|
|
s.Require().NoError(err, "获取 action '%s' 失败", actionName)
|
|
}
|
|
|
|
// 创建条件流
|
|
s.flow = condflow.New("test-flow")
|
|
}
|
|
|
|
// TearDownTest 在每个测试后运行
|
|
func (s *CondFlowTestSuite) TearDownTest() {
|
|
if s.app != nil {
|
|
s.app.Shutdown()
|
|
}
|
|
}
|
|
|
|
// TestSmallAmountAutoApproval 测试小额自动审批
|
|
func (s *CondFlowTestSuite) TestSmallAmountAutoApproval() {
|
|
// 创建条件: 金额 <= 1000
|
|
cond := condition.New(condition.Describe("小额自动审批"))
|
|
cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("1000", condition.STRING)))
|
|
|
|
config, _ := fieldx.SchemaFromMap(map[string]any{
|
|
"notify": map[string]any{
|
|
"type": "string",
|
|
"value": "true",
|
|
},
|
|
"message": map[string]any{
|
|
"type": "string",
|
|
"value": "申请已自动通过",
|
|
},
|
|
})
|
|
|
|
// 创建条件分支,使用 action 名称字符串
|
|
condCase := condflow.NewCondCase("auto-approve-small", cond, "Approval/ApproveExecutor@AutoApprove").
|
|
WithPriority(100).
|
|
WithActionConfig(config)
|
|
|
|
// 添加到流程
|
|
s.flow.AddCase(condCase)
|
|
|
|
// 准备输入数据
|
|
input := reflux.New(map[string]any{
|
|
"amount": 500.0,
|
|
"user": map[string]any{
|
|
"id": 1,
|
|
"credit_score": 80,
|
|
},
|
|
})
|
|
|
|
// 执行流程
|
|
err := s.flow.Run(s.app, input, base.GetSystemUser())
|
|
s.NoError(err)
|
|
}
|
|
|
|
// TestManagerApproval 测试经理审批
|
|
func (s *CondFlowTestSuite) TestManagerApproval() {
|
|
// 创建条件: 1000 < 金额 <= 10000
|
|
cond := condition.New(condition.Describe("经理审批"))
|
|
cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.GT), condition.Token("1000", condition.STRING))).
|
|
SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("10000", condition.STRING)))
|
|
|
|
config, _ := fieldx.SchemaFromMap(map[string]any{
|
|
"approver_role": map[string]any{
|
|
"type": "string",
|
|
"value": "manager",
|
|
},
|
|
"timeout_hours": map[string]any{
|
|
"type": "string",
|
|
"value": "24",
|
|
},
|
|
})
|
|
|
|
// 创建条件分支,使用 action 名称字符串
|
|
condCase := condflow.NewCondCase("manager-approval", cond, "Approval/ApproveExecutor@Manager").
|
|
WithPriority(90).
|
|
WithActionConfig(config)
|
|
|
|
// 添加到流程
|
|
s.flow.AddCase(condCase)
|
|
|
|
// 准备输入数据
|
|
input := reflux.New(map[string]any{
|
|
"amount": 5000.0,
|
|
"user": map[string]any{
|
|
"id": 1,
|
|
"credit_score": 80,
|
|
},
|
|
})
|
|
|
|
// 执行流程
|
|
err := s.flow.Run(s.app, input, base.GetSystemUser())
|
|
s.NoError(err)
|
|
}
|
|
|
|
// TestLowCreditReject 测试低信用评分拒绝
|
|
func (s *CondFlowTestSuite) TestLowCreditReject() {
|
|
// 创建条件: 用户信用评分 < 60
|
|
cond := condition.New(condition.Describe("信用不足拒绝"))
|
|
cond.SetExpr(condition.NewExpr("@", "user->>'credit_score'", condition.Operator(condition.LT), condition.Token("60", condition.STRING)))
|
|
|
|
config, _ := fieldx.SchemaFromMap(map[string]any{
|
|
"reason": map[string]any{
|
|
"type": "string",
|
|
"value": "信用评分不足",
|
|
},
|
|
"notify": map[string]any{
|
|
"type": "string",
|
|
"value": "true",
|
|
},
|
|
"suggest_retry": map[string]any{
|
|
"type": "string",
|
|
"value": "false",
|
|
},
|
|
})
|
|
|
|
// 创建条件分支,使用 action 名称字符串
|
|
condCase := condflow.NewCondCase("reject-low-credit", cond, "Approval/ApproveExecutor@Reject").
|
|
WithPriority(200).
|
|
WithActionConfig(config)
|
|
|
|
// 添加到流程
|
|
s.flow.AddCase(condCase)
|
|
|
|
// 准备输入数据
|
|
input := reflux.New(map[string]any{
|
|
"amount": 500.0,
|
|
"user": map[string]any{
|
|
"id": 1,
|
|
"credit_score": 50,
|
|
},
|
|
})
|
|
|
|
// 执行流程
|
|
err := s.flow.Run(s.app, input, base.GetSystemUser())
|
|
s.NoError(err)
|
|
}
|
|
|
|
// TestMultipleCases 测试多个条件分支
|
|
func (s *CondFlowTestSuite) TestMultipleCases() {
|
|
// Case 1: 小额自动审批
|
|
case1Cond := condition.New(condition.Describe("小额自动审批"))
|
|
case1Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("1000", condition.STRING)))
|
|
|
|
case1 := condflow.NewCondCase("auto-approve-small", case1Cond, "Approval/ApproveExecutor@AutoApprove").
|
|
WithPriority(100)
|
|
|
|
// Case 2: 经理审批
|
|
case2Cond := condition.New(condition.Describe("经理审批"))
|
|
case2Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.GT), condition.Token("1000", condition.STRING))).
|
|
SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.LE), condition.Token("10000", condition.STRING)))
|
|
|
|
case2 := condflow.NewCondCase("manager-approval", case2Cond, "Approval/ApproveExecutor@Manager").
|
|
WithPriority(90)
|
|
|
|
// Case 3: 总监审批
|
|
case3Cond := condition.New(condition.Describe("总监审批"))
|
|
case3Cond.SetExpr(condition.NewExpr("@", "amount", condition.Operator(condition.GT), condition.Token("10000", condition.STRING)))
|
|
|
|
case3 := condflow.NewCondCase("director-approval", case3Cond, "Approval/ApproveExecutor@Director").
|
|
WithPriority(80)
|
|
|
|
// Case 4: 低信用拒绝(最高优先级)
|
|
case4Cond := condition.New(condition.Describe("信用不足拒绝"))
|
|
case4Cond.SetExpr(condition.NewExpr("@", "user->>'credit_score'", condition.Operator(condition.LT), condition.Token("60", condition.STRING)))
|
|
|
|
case4Config, _ := fieldx.SchemaFromMap(map[string]any{
|
|
"reason": map[string]any{
|
|
"type": "string",
|
|
"value": "信用评分不足",
|
|
},
|
|
})
|
|
|
|
case4 := condflow.NewCondCase("reject-low-credit", case4Cond, "Approval/ApproveExecutor@Reject").
|
|
WithPriority(200).
|
|
WithActionConfig(case4Config)
|
|
|
|
// 添加所有条件分支
|
|
s.flow.AddCase(case4).
|
|
AddCase(case1).
|
|
AddCase(case2).
|
|
AddCase(case3)
|
|
|
|
// 测试不同的输入数据
|
|
testCases := []struct {
|
|
name string
|
|
input map[string]any
|
|
expect string
|
|
}{
|
|
{
|
|
name: "小额正常用户",
|
|
input: map[string]any{
|
|
"amount": 500.0,
|
|
"user": map[string]any{
|
|
"id": 1,
|
|
"credit_score": 80,
|
|
},
|
|
},
|
|
expect: "auto-approve",
|
|
},
|
|
{
|
|
name: "中额正常用户",
|
|
input: map[string]any{
|
|
"amount": 5000.0,
|
|
"user": map[string]any{
|
|
"id": 1,
|
|
"credit_score": 80,
|
|
},
|
|
},
|
|
expect: "manager-approve",
|
|
},
|
|
{
|
|
name: "大额正常用户",
|
|
input: map[string]any{
|
|
"amount": 15000.0,
|
|
"user": map[string]any{
|
|
"id": 1,
|
|
"credit_score": 80,
|
|
},
|
|
},
|
|
expect: "director-approve",
|
|
},
|
|
{
|
|
name: "低信用用户",
|
|
input: map[string]any{
|
|
"amount": 500.0,
|
|
"user": map[string]any{
|
|
"id": 1,
|
|
"credit_score": 50,
|
|
},
|
|
},
|
|
expect: "reject",
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
s.Run(tc.name, func() {
|
|
input := reflux.New(tc.input)
|
|
err := s.flow.Run(s.app, input, base.GetSystemUser())
|
|
s.NoError(err)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSuite 运行测试套件
|
|
func TestCondFlow(t *testing.T) {
|
|
suite.Run(t, new(CondFlowTestSuite))
|
|
}
|