增加顺序修复

This commit is contained in:
2025-09-14 15:18:35 +08:00
parent 8ceff5c3c7
commit 4ddb2c5448
2 changed files with 178 additions and 42 deletions

View File

@@ -2,6 +2,7 @@ package models
import (
"fmt"
"sort"
"gorm.io/datatypes"
"gorm.io/gorm"
@@ -79,6 +80,42 @@ func (p Plan) ValidateExecutionOrder() error {
return nil
}
// ReorderSteps 重新排序计划中的步骤(任务或子计划),使其 ExecutionOrder 从 1 开始且连续。
// 这个方法假设重复的顺序已经被其他方法验证过它只负责修复断层和不从1开始的序列。
func (p *Plan) ReorderSteps() {
switch p.ContentType {
case PlanContentTypeTasks:
if len(p.Tasks) == 0 {
return
}
// 1. 按当前的 ExecutionOrder 对任务进行排序
sort.Slice(p.Tasks, func(i, j int) bool {
return p.Tasks[i].ExecutionOrder < p.Tasks[j].ExecutionOrder
})
// 2. 重新分配连续的 ExecutionOrder
for i := range p.Tasks {
p.Tasks[i].ExecutionOrder = i + 1
}
case PlanContentTypeSubPlans:
if len(p.SubPlans) == 0 {
return
}
// 1. 按当前的 ExecutionOrder 对子计划进行排序
sort.Slice(p.SubPlans, func(i, j int) bool {
return p.SubPlans[i].ExecutionOrder < p.SubPlans[j].ExecutionOrder
})
// 2. 重新分配连续的 ExecutionOrder
for i := range p.SubPlans {
p.SubPlans[i].ExecutionOrder = i + 1
}
}
}
// SubPlan 代表作为另一个计划一部分的子计划,具有执行顺序
type SubPlan struct {
gorm.Model

View File

@@ -1,22 +1,25 @@
package models_test
import (
"fmt"
"sort"
"testing"
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
"github.com/stretchr/testify/assert"
)
func TestPlan_ValidateExecutionOrder(t *testing.T) {
tests := []struct {
func TestPlan_ReorderSteps(t *testing.T) {
type testCase struct {
name string
plan models.Plan
expectedError string // 期望的错误信息如果为nil则表示不期望错误
}{
initialPlan *models.Plan
expectedOrders []int
}
testCases := []testCase{
// --- Test Cases for Tasks ---
{
name: "任务类型-无重复执行顺序",
plan: models.Plan{
name: "Tasks: 完美顺序",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeTasks,
Tasks: []models.Task{
{ExecutionOrder: 1},
@@ -24,31 +27,78 @@ func TestPlan_ValidateExecutionOrder(t *testing.T) {
{ExecutionOrder: 3},
},
},
expectedError: "",
expectedOrders: []int{1, 2, 3},
},
{
name: "任务类型-重复执行顺序",
plan: models.Plan{
name: "Tasks: 有间断",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeTasks,
Tasks: []models.Task{
{ExecutionOrder: 1},
{ExecutionOrder: 2},
{ExecutionOrder: 1}, // 重复
{ExecutionOrder: 3},
{ExecutionOrder: 5},
},
},
expectedError: fmt.Sprintf("任务执行顺序重复: %d", 1),
expectedOrders: []int{1, 2, 3},
},
{
name: "任务类型-空任务列表",
plan: models.Plan{
name: "Tasks: 从0开始",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeTasks,
Tasks: []models.Task{
{ExecutionOrder: 0},
{ExecutionOrder: 1},
{ExecutionOrder: 2},
},
},
expectedOrders: []int{1, 2, 3},
},
{
name: "Tasks: 完全无序",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeTasks,
Tasks: []models.Task{
{ExecutionOrder: 8},
{ExecutionOrder: 2},
{ExecutionOrder: 4},
},
},
expectedOrders: []int{1, 2, 3},
},
{
name: "Tasks: 包含负数",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeTasks,
Tasks: []models.Task{
{ExecutionOrder: -5},
{ExecutionOrder: 10},
{ExecutionOrder: 2},
},
},
expectedOrders: []int{1, 2, 3},
},
{
name: "Tasks: 空切片",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeTasks,
Tasks: []models.Task{},
},
expectedError: "",
expectedOrders: []int{},
},
{
name: "子计划类型-无重复执行顺序",
plan: models.Plan{
name: "Tasks: 单个元素",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeTasks,
Tasks: []models.Task{
{ExecutionOrder: 100},
},
},
expectedOrders: []int{1},
},
// --- Test Cases for SubPlans ---
{
name: "SubPlans: 完美顺序",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeSubPlans,
SubPlans: []models.SubPlan{
{ExecutionOrder: 1},
@@ -56,48 +106,97 @@ func TestPlan_ValidateExecutionOrder(t *testing.T) {
{ExecutionOrder: 3},
},
},
expectedError: "",
expectedOrders: []int{1, 2, 3},
},
{
name: "子计划类型-重复执行顺序",
plan: models.Plan{
name: "SubPlans: 有间断",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeSubPlans,
SubPlans: []models.SubPlan{
{ExecutionOrder: 1},
{ExecutionOrder: 2},
{ExecutionOrder: 1}, // 重复
{ExecutionOrder: 3},
{ExecutionOrder: 5},
},
},
expectedError: fmt.Sprintf("子计划执行顺序重复: %d", 1),
expectedOrders: []int{1, 2, 3},
},
{
name: "子计划类型-空子计划列表",
plan: models.Plan{
name: "SubPlans: 从0开始",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeSubPlans,
SubPlans: []models.SubPlan{
{ExecutionOrder: 0},
{ExecutionOrder: 1},
{ExecutionOrder: 2},
},
},
expectedOrders: []int{1, 2, 3},
},
{
name: "SubPlans: 完全无序",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeSubPlans,
SubPlans: []models.SubPlan{
{ExecutionOrder: 8},
{ExecutionOrder: 2},
{ExecutionOrder: 4},
},
},
expectedOrders: []int{1, 2, 3},
},
{
name: "SubPlans: 包含负数",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeSubPlans,
SubPlans: []models.SubPlan{
{ExecutionOrder: -5},
{ExecutionOrder: 10},
{ExecutionOrder: 2},
},
},
expectedOrders: []int{1, 2, 3},
},
{
name: "SubPlans: 空切片",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeSubPlans,
SubPlans: []models.SubPlan{},
},
expectedError: "",
expectedOrders: []int{},
},
{
name: "未知内容类型",
plan: models.Plan{
ContentType: "UNKNOWN_TYPE", // 未知类型
Tasks: []models.Task{{ExecutionOrder: 1}},
name: "SubPlans: 单个元素",
initialPlan: &models.Plan{
ContentType: models.PlanContentTypeSubPlans,
SubPlans: []models.SubPlan{
{ExecutionOrder: 100},
},
expectedError: "", // 对于未知类型ValidateExecutionOrder 不会返回错误,因为它只处理已知类型
},
expectedOrders: []int{1},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.plan.ValidateExecutionOrder()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// 调用被测试的方法
tc.initialPlan.ReorderSteps()
if tt.expectedError != "" {
assert.Error(t, err)
assert.Contains(t, err.Error(), tt.expectedError)
} else {
assert.NoError(t, err)
// 提取并验证最终的顺序
finalOrders := make([]int, 0)
if tc.initialPlan.ContentType == models.PlanContentTypeTasks {
for _, task := range tc.initialPlan.Tasks {
finalOrders = append(finalOrders, task.ExecutionOrder)
}
} else if tc.initialPlan.ContentType == models.PlanContentTypeSubPlans {
for _, subPlan := range tc.initialPlan.SubPlans {
finalOrders = append(finalOrders, subPlan.ExecutionOrder)
}
}
// 对 finalOrders 进行排序,以确保比较的一致性,因为 ReorderSteps 后的顺序是固定的
sort.Ints(finalOrders)
assert.Equal(t, tc.expectedOrders, finalOrders, "The final execution orders should be a continuous sequence starting from 1.")
})
}
}