增加顺序修复
This commit is contained in:
@@ -2,6 +2,7 @@ package models
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"gorm.io/datatypes"
|
"gorm.io/datatypes"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -79,6 +80,42 @@ func (p Plan) ValidateExecutionOrder() error {
|
|||||||
return nil
|
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 代表作为另一个计划一部分的子计划,具有执行顺序
|
// SubPlan 代表作为另一个计划一部分的子计划,具有执行顺序
|
||||||
type SubPlan struct {
|
type SubPlan struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
|
|||||||
@@ -1,22 +1,25 @@
|
|||||||
package models_test
|
package models_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"sort"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPlan_ValidateExecutionOrder(t *testing.T) {
|
func TestPlan_ReorderSteps(t *testing.T) {
|
||||||
tests := []struct {
|
type testCase struct {
|
||||||
name string
|
name string
|
||||||
plan models.Plan
|
initialPlan *models.Plan
|
||||||
expectedError string // 期望的错误信息,如果为nil则表示不期望错误
|
expectedOrders []int
|
||||||
}{
|
}
|
||||||
|
|
||||||
|
testCases := []testCase{
|
||||||
|
// --- Test Cases for Tasks ---
|
||||||
{
|
{
|
||||||
name: "任务类型-无重复执行顺序",
|
name: "Tasks: 完美顺序",
|
||||||
plan: models.Plan{
|
initialPlan: &models.Plan{
|
||||||
ContentType: models.PlanContentTypeTasks,
|
ContentType: models.PlanContentTypeTasks,
|
||||||
Tasks: []models.Task{
|
Tasks: []models.Task{
|
||||||
{ExecutionOrder: 1},
|
{ExecutionOrder: 1},
|
||||||
@@ -24,31 +27,78 @@ func TestPlan_ValidateExecutionOrder(t *testing.T) {
|
|||||||
{ExecutionOrder: 3},
|
{ExecutionOrder: 3},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedError: "",
|
expectedOrders: []int{1, 2, 3},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "任务类型-重复执行顺序",
|
name: "Tasks: 有间断",
|
||||||
plan: models.Plan{
|
initialPlan: &models.Plan{
|
||||||
ContentType: models.PlanContentTypeTasks,
|
ContentType: models.PlanContentTypeTasks,
|
||||||
Tasks: []models.Task{
|
Tasks: []models.Task{
|
||||||
{ExecutionOrder: 1},
|
{ExecutionOrder: 1},
|
||||||
{ExecutionOrder: 2},
|
{ExecutionOrder: 3},
|
||||||
{ExecutionOrder: 1}, // 重复
|
{ExecutionOrder: 5},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedError: fmt.Sprintf("任务执行顺序重复: %d", 1),
|
expectedOrders: []int{1, 2, 3},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "任务类型-空任务列表",
|
name: "Tasks: 从0开始",
|
||||||
plan: models.Plan{
|
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,
|
ContentType: models.PlanContentTypeTasks,
|
||||||
Tasks: []models.Task{},
|
Tasks: []models.Task{},
|
||||||
},
|
},
|
||||||
expectedError: "",
|
expectedOrders: []int{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "子计划类型-无重复执行顺序",
|
name: "Tasks: 单个元素",
|
||||||
plan: models.Plan{
|
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,
|
ContentType: models.PlanContentTypeSubPlans,
|
||||||
SubPlans: []models.SubPlan{
|
SubPlans: []models.SubPlan{
|
||||||
{ExecutionOrder: 1},
|
{ExecutionOrder: 1},
|
||||||
@@ -56,48 +106,97 @@ func TestPlan_ValidateExecutionOrder(t *testing.T) {
|
|||||||
{ExecutionOrder: 3},
|
{ExecutionOrder: 3},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedError: "",
|
expectedOrders: []int{1, 2, 3},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "子计划类型-重复执行顺序",
|
name: "SubPlans: 有间断",
|
||||||
plan: models.Plan{
|
initialPlan: &models.Plan{
|
||||||
ContentType: models.PlanContentTypeSubPlans,
|
ContentType: models.PlanContentTypeSubPlans,
|
||||||
SubPlans: []models.SubPlan{
|
SubPlans: []models.SubPlan{
|
||||||
{ExecutionOrder: 1},
|
{ExecutionOrder: 1},
|
||||||
{ExecutionOrder: 2},
|
{ExecutionOrder: 3},
|
||||||
{ExecutionOrder: 1}, // 重复
|
{ExecutionOrder: 5},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedError: fmt.Sprintf("子计划执行顺序重复: %d", 1),
|
expectedOrders: []int{1, 2, 3},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "子计划类型-空子计划列表",
|
name: "SubPlans: 从0开始",
|
||||||
plan: models.Plan{
|
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,
|
ContentType: models.PlanContentTypeSubPlans,
|
||||||
SubPlans: []models.SubPlan{},
|
SubPlans: []models.SubPlan{},
|
||||||
},
|
},
|
||||||
expectedError: "",
|
expectedOrders: []int{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "未知内容类型",
|
name: "SubPlans: 单个元素",
|
||||||
plan: models.Plan{
|
initialPlan: &models.Plan{
|
||||||
ContentType: "UNKNOWN_TYPE", // 未知类型
|
ContentType: models.PlanContentTypeSubPlans,
|
||||||
Tasks: []models.Task{{ExecutionOrder: 1}},
|
SubPlans: []models.SubPlan{
|
||||||
|
{ExecutionOrder: 100},
|
||||||
},
|
},
|
||||||
expectedError: "", // 对于未知类型,ValidateExecutionOrder 不会返回错误,因为它只处理已知类型
|
},
|
||||||
|
expectedOrders: []int{1},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tc := range testCases {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
err := tt.plan.ValidateExecutionOrder()
|
// 调用被测试的方法
|
||||||
|
tc.initialPlan.ReorderSteps()
|
||||||
|
|
||||||
if tt.expectedError != "" {
|
// 提取并验证最终的顺序
|
||||||
assert.Error(t, err)
|
finalOrders := make([]int, 0)
|
||||||
assert.Contains(t, err.Error(), tt.expectedError)
|
if tc.initialPlan.ContentType == models.PlanContentTypeTasks {
|
||||||
} else {
|
for _, task := range tc.initialPlan.Tasks {
|
||||||
assert.NoError(t, err)
|
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.")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user