1. 增加重复顺序校验
2. 增加测试用例
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"gorm.io/datatypes"
|
"gorm.io/datatypes"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
@@ -54,6 +56,29 @@ func (Plan) TableName() string {
|
|||||||
return "plans"
|
return "plans"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateExecutionOrder 校验计划中的步骤或子计划顺序不能有重复的
|
||||||
|
func (p Plan) ValidateExecutionOrder() error {
|
||||||
|
orderMap := make(map[int]bool)
|
||||||
|
|
||||||
|
switch p.ContentType {
|
||||||
|
case PlanContentTypeTasks:
|
||||||
|
for _, task := range p.Tasks {
|
||||||
|
if orderMap[task.ExecutionOrder] {
|
||||||
|
return fmt.Errorf("任务执行顺序重复: %d", task.ExecutionOrder)
|
||||||
|
}
|
||||||
|
orderMap[task.ExecutionOrder] = true
|
||||||
|
}
|
||||||
|
case PlanContentTypeSubPlans:
|
||||||
|
for _, subPlan := range p.SubPlans {
|
||||||
|
if orderMap[subPlan.ExecutionOrder] {
|
||||||
|
return fmt.Errorf("子计划执行顺序重复: %d", subPlan.ExecutionOrder)
|
||||||
|
}
|
||||||
|
orderMap[subPlan.ExecutionOrder] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// SubPlan 代表作为另一个计划一部分的子计划,具有执行顺序
|
// SubPlan 代表作为另一个计划一部分的子计划,具有执行顺序
|
||||||
type SubPlan struct {
|
type SubPlan struct {
|
||||||
gorm.Model
|
gorm.Model
|
||||||
|
|||||||
103
internal/infra/models/plan_test.go
Normal file
103
internal/infra/models/plan_test.go
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
package models_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.huangwc.com/pig/pig-farm-controller/internal/infra/models"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPlan_ValidateExecutionOrder(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
plan models.Plan
|
||||||
|
expectedError string // 期望的错误信息,如果为nil则表示不期望错误
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "任务类型-无重复执行顺序",
|
||||||
|
plan: models.Plan{
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
Tasks: []models.Task{
|
||||||
|
{ExecutionOrder: 1},
|
||||||
|
{ExecutionOrder: 2},
|
||||||
|
{ExecutionOrder: 3},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "任务类型-重复执行顺序",
|
||||||
|
plan: models.Plan{
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
Tasks: []models.Task{
|
||||||
|
{ExecutionOrder: 1},
|
||||||
|
{ExecutionOrder: 2},
|
||||||
|
{ExecutionOrder: 1}, // 重复
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: fmt.Sprintf("任务执行顺序重复: %d", 1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "任务类型-空任务列表",
|
||||||
|
plan: models.Plan{
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
Tasks: []models.Task{},
|
||||||
|
},
|
||||||
|
expectedError: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "子计划类型-无重复执行顺序",
|
||||||
|
plan: models.Plan{
|
||||||
|
ContentType: models.PlanContentTypeSubPlans,
|
||||||
|
SubPlans: []models.SubPlan{
|
||||||
|
{ExecutionOrder: 1},
|
||||||
|
{ExecutionOrder: 2},
|
||||||
|
{ExecutionOrder: 3},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "子计划类型-重复执行顺序",
|
||||||
|
plan: models.Plan{
|
||||||
|
ContentType: models.PlanContentTypeSubPlans,
|
||||||
|
SubPlans: []models.SubPlan{
|
||||||
|
{ExecutionOrder: 1},
|
||||||
|
{ExecutionOrder: 2},
|
||||||
|
{ExecutionOrder: 1}, // 重复
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: fmt.Sprintf("子计划执行顺序重复: %d", 1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "子计划类型-空子计划列表",
|
||||||
|
plan: models.Plan{
|
||||||
|
ContentType: models.PlanContentTypeSubPlans,
|
||||||
|
SubPlans: []models.SubPlan{},
|
||||||
|
},
|
||||||
|
expectedError: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "未知内容类型",
|
||||||
|
plan: models.Plan{
|
||||||
|
ContentType: "UNKNOWN_TYPE", // 未知类型
|
||||||
|
Tasks: []models.Task{{ExecutionOrder: 1}},
|
||||||
|
},
|
||||||
|
expectedError: "", // 对于未知类型,ValidateExecutionOrder 不会返回错误,因为它只处理已知类型
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
err := tt.plan.ValidateExecutionOrder()
|
||||||
|
|
||||||
|
if tt.expectedError != "" {
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), tt.expectedError)
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -125,6 +125,11 @@ func (r *gormPlanRepository) Create(plan *models.Plan) error {
|
|||||||
return ErrMixedContent
|
return ErrMixedContent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查是否有重复的执行顺序
|
||||||
|
if err := plan.ValidateExecutionOrder(); err != nil {
|
||||||
|
return fmt.Errorf("计划 (ID: %d) 的执行顺序无效: %w", plan.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
// 如果是子计划类型,验证所有子计划是否存在且ID不为0
|
// 如果是子计划类型,验证所有子计划是否存在且ID不为0
|
||||||
if plan.ContentType == models.PlanContentTypeSubPlans {
|
if plan.ContentType == models.PlanContentTypeSubPlans {
|
||||||
childIDsToValidate := make(map[uint]bool)
|
childIDsToValidate := make(map[uint]bool)
|
||||||
@@ -156,28 +161,6 @@ func (r *gormPlanRepository) Create(plan *models.Plan) error {
|
|||||||
if err := tx.Create(plan).Error; err != nil {
|
if err := tx.Create(plan).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 处理子计划关联 (如果 ContentType 是 sub_plans)
|
|
||||||
// GORM 不会自动创建 SubPlan 关联记录,需要手动处理
|
|
||||||
if plan.ContentType == models.PlanContentTypeSubPlans {
|
|
||||||
// 收集所有 SubPlan 关联,设置 ParentPlanID
|
|
||||||
var subPlanLinksToCreate []models.SubPlan
|
|
||||||
for i := range plan.SubPlans {
|
|
||||||
plan.SubPlans[i].ParentPlanID = plan.ID // 设置父计划ID
|
|
||||||
// 确保 ChildPlanID 被正确设置,因为 ChildPlan 对象可能只在内存中
|
|
||||||
if plan.SubPlans[i].ChildPlanID == 0 && plan.SubPlans[i].ChildPlan != nil {
|
|
||||||
plan.SubPlans[i].ChildPlanID = plan.SubPlans[i].ChildPlan.ID
|
|
||||||
}
|
|
||||||
subPlanLinksToCreate = append(subPlanLinksToCreate, plan.SubPlans[i])
|
|
||||||
}
|
|
||||||
|
|
||||||
// 批量创建 SubPlan 关联记录
|
|
||||||
if len(subPlanLinksToCreate) > 0 {
|
|
||||||
if err := tx.CreateInBatches(subPlanLinksToCreate, 100).Error; err != nil { // 批量大小100
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -214,7 +197,12 @@ func (r *gormPlanRepository) validatePlanTree(tx *gorm.DB, plan *models.Plan) er
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. 一次性数据库存在性校验
|
// 3. 检查是否有重复的执行顺序
|
||||||
|
if err := plan.ValidateExecutionOrder(); err != nil {
|
||||||
|
return fmt.Errorf("计划 (ID: %d) 的执行顺序无效: %w", plan.ID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 一次性数据库存在性校验
|
||||||
var idsToCheck []uint
|
var idsToCheck []uint
|
||||||
for id := range allIDs {
|
for id := range allIDs {
|
||||||
idsToCheck = append(idsToCheck, id)
|
idsToCheck = append(idsToCheck, id)
|
||||||
@@ -229,7 +217,6 @@ func (r *gormPlanRepository) validatePlanTree(tx *gorm.DB, plan *models.Plan) er
|
|||||||
return ErrNodeDoesNotExist
|
return ErrNodeDoesNotExist
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -432,8 +432,8 @@ func TestUpdatePlan_Validation(t *testing.T) {
|
|||||||
planC.SubPlans = []models.SubPlan{{ChildPlanID: 4, ChildPlan: planD}}
|
planC.SubPlans = []models.SubPlan{{ChildPlanID: 4, ChildPlan: planD}}
|
||||||
planA.ContentType = models.PlanContentTypeSubPlans
|
planA.ContentType = models.PlanContentTypeSubPlans
|
||||||
planA.SubPlans = []models.SubPlan{
|
planA.SubPlans = []models.SubPlan{
|
||||||
{ChildPlanID: 2, ChildPlan: planB},
|
{ChildPlanID: 2, ChildPlan: planB, ExecutionOrder: 1},
|
||||||
{ChildPlanID: 3, ChildPlan: planC},
|
{ChildPlanID: 3, ChildPlan: planC, ExecutionOrder: 2},
|
||||||
}
|
}
|
||||||
return planA
|
return planA
|
||||||
},
|
},
|
||||||
@@ -466,8 +466,8 @@ func TestUpdatePlan_Validation(t *testing.T) {
|
|||||||
buildInput: func() *models.Plan {
|
buildInput: func() *models.Plan {
|
||||||
planA.ContentType = models.PlanContentTypeSubPlans
|
planA.ContentType = models.PlanContentTypeSubPlans
|
||||||
planA.SubPlans = []models.SubPlan{
|
planA.SubPlans = []models.SubPlan{
|
||||||
{ChildPlanID: 2, ChildPlan: planB},
|
{ChildPlanID: 2, ChildPlan: planB, ExecutionOrder: 1},
|
||||||
{ChildPlanID: 3, ChildPlan: planC}, // C 不存在
|
{ChildPlanID: 3, ChildPlan: planC, ExecutionOrder: 2}, // C 不存在
|
||||||
}
|
}
|
||||||
return planA
|
return planA
|
||||||
},
|
},
|
||||||
@@ -532,6 +532,37 @@ func TestUpdatePlan_Validation(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectedError: "不能同时包含任务和子计划",
|
expectedError: "不能同时包含任务和子计划",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "错误-任务执行顺序重复",
|
||||||
|
setupDB: func(db *gorm.DB) {
|
||||||
|
db.Create(&models.Plan{Model: gorm.Model{ID: 1}})
|
||||||
|
},
|
||||||
|
buildInput: func() *models.Plan {
|
||||||
|
planA.ContentType = models.PlanContentTypeTasks
|
||||||
|
planA.Tasks = []models.Task{
|
||||||
|
{Name: "Task 1", ExecutionOrder: 1},
|
||||||
|
{Name: "Task 2", ExecutionOrder: 1}, // 重复的顺序
|
||||||
|
}
|
||||||
|
return planA
|
||||||
|
},
|
||||||
|
expectedError: fmt.Sprintf("任务执行顺序重复: %d", 1),
|
||||||
|
}, {
|
||||||
|
name: "错误-子计划执行顺序重复",
|
||||||
|
setupDB: func(db *gorm.DB) {
|
||||||
|
db.Create(&models.Plan{Model: gorm.Model{ID: 1}})
|
||||||
|
db.Create(&models.Plan{Model: gorm.Model{ID: 10}})
|
||||||
|
db.Create(&models.Plan{Model: gorm.Model{ID: 11}})
|
||||||
|
},
|
||||||
|
buildInput: func() *models.Plan {
|
||||||
|
planA.ContentType = models.PlanContentTypeSubPlans
|
||||||
|
planA.SubPlans = []models.SubPlan{
|
||||||
|
{ChildPlanID: 10, ChildPlan: &models.Plan{Model: gorm.Model{ID: 10}}, ExecutionOrder: 1},
|
||||||
|
{ChildPlanID: 11, ChildPlan: &models.Plan{Model: gorm.Model{ID: 11}}, ExecutionOrder: 1}, // 重复的顺序
|
||||||
|
}
|
||||||
|
return planA
|
||||||
|
},
|
||||||
|
expectedError: fmt.Sprintf("子计划执行顺序重复: %d", 1),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
@@ -1024,3 +1055,243 @@ func TestUpdatePlan_Reconciliation(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createExistingPlan 辅助函数,用于在数据库中创建已存在的计划
|
||||||
|
func createExistingPlan(db *gorm.DB, name string, contentType models.PlanContentType) *models.Plan {
|
||||||
|
plan := &models.Plan{
|
||||||
|
Name: name,
|
||||||
|
ContentType: contentType,
|
||||||
|
}
|
||||||
|
db.Create(plan)
|
||||||
|
return plan
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPlanRepository_Create(t *testing.T) {
|
||||||
|
type testCase struct {
|
||||||
|
name string
|
||||||
|
setupDB func(db *gorm.DB) // 准备数据库的初始状态
|
||||||
|
inputPlan *models.Plan // 传入 Create 方法的计划对象
|
||||||
|
expectedError error // 期望的错误类型
|
||||||
|
verifyDB func(t *testing.T, db *gorm.DB, createdPlan *models.Plan) // 验证数据库状态
|
||||||
|
}
|
||||||
|
|
||||||
|
testCases := []testCase{
|
||||||
|
{
|
||||||
|
name: "成功创建-只包含基本信息",
|
||||||
|
setupDB: func(db *gorm.DB) {
|
||||||
|
// 无需额外设置
|
||||||
|
},
|
||||||
|
inputPlan: &models.Plan{
|
||||||
|
Name: "简单计划",
|
||||||
|
Description: "一个不包含任务或子计划的简单计划",
|
||||||
|
ContentType: models.PlanContentTypeTasks, // 修改为有效的 ContentType
|
||||||
|
Tasks: []models.Task{}, // 明确为空任务列表
|
||||||
|
},
|
||||||
|
expectedError: nil,
|
||||||
|
verifyDB: func(t *testing.T, db *gorm.DB, createdPlan *models.Plan) {
|
||||||
|
assert.NotZero(t, createdPlan.ID, "创建后计划ID不应为0")
|
||||||
|
var foundPlan models.Plan
|
||||||
|
err := db.First(&foundPlan, createdPlan.ID).Error
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, "简单计划", foundPlan.Name)
|
||||||
|
assert.Equal(t, models.PlanContentTypeTasks, foundPlan.ContentType)
|
||||||
|
var tasks []models.Task
|
||||||
|
db.Where("plan_id = ?", createdPlan.ID).Find(&tasks)
|
||||||
|
assert.Len(t, tasks, 0, "不应创建任何任务")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "成功创建-包含任务",
|
||||||
|
setupDB: func(db *gorm.DB) {
|
||||||
|
// 无需额外设置
|
||||||
|
},
|
||||||
|
inputPlan: &models.Plan{
|
||||||
|
Name: "任务计划",
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
Tasks: []models.Task{
|
||||||
|
{Name: "任务A", ExecutionOrder: 1},
|
||||||
|
{Name: "任务B", ExecutionOrder: 2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: nil,
|
||||||
|
verifyDB: func(t *testing.T, db *gorm.DB, createdPlan *models.Plan) {
|
||||||
|
assert.NotZero(t, createdPlan.ID, "计划ID不应为0")
|
||||||
|
var foundPlan models.Plan
|
||||||
|
db.Preload("Tasks").First(&foundPlan, createdPlan.ID)
|
||||||
|
assert.Len(t, foundPlan.Tasks, 2, "应创建两个任务")
|
||||||
|
assert.NotZero(t, foundPlan.Tasks[0].ID, "任务ID不应为0")
|
||||||
|
assert.Equal(t, "任务A", foundPlan.Tasks[0].Name)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "成功创建-包含子计划关联",
|
||||||
|
setupDB: func(db *gorm.DB) {
|
||||||
|
// 预先创建子计划实体,使用有效的 ContentType
|
||||||
|
createExistingPlan(db, "子计划1", models.PlanContentTypeTasks)
|
||||||
|
createExistingPlan(db, "子计划2", models.PlanContentTypeTasks)
|
||||||
|
},
|
||||||
|
inputPlan: &models.Plan{
|
||||||
|
Name: "父计划",
|
||||||
|
ContentType: models.PlanContentTypeSubPlans,
|
||||||
|
SubPlans: []models.SubPlan{
|
||||||
|
{ChildPlanID: 1, ExecutionOrder: 1, ChildPlan: &models.Plan{Model: gorm.Model{ID: 1}}}, // 关联已存在的子计划1
|
||||||
|
{ChildPlanID: 2, ExecutionOrder: 2, ChildPlan: &models.Plan{Model: gorm.Model{ID: 2}}}, // 关联已存在的子计划2
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: nil,
|
||||||
|
verifyDB: func(t *testing.T, db *gorm.DB, createdPlan *models.Plan) {
|
||||||
|
assert.NotZero(t, createdPlan.ID, "创建后计划ID不应为0")
|
||||||
|
|
||||||
|
// 直接查询 SubPlan 关联记录
|
||||||
|
var foundSubPlanLinks []models.SubPlan
|
||||||
|
err := db.Where("parent_plan_id = ?", createdPlan.ID).Find(&foundSubPlanLinks).Error
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Len(t, foundSubPlanLinks, 2, "应创建两个子计划关联")
|
||||||
|
assert.NotZero(t, foundSubPlanLinks[0].ID, "子计划关联ID不应为0")
|
||||||
|
assert.Equal(t, createdPlan.ID, foundSubPlanLinks[0].ParentPlanID)
|
||||||
|
assert.Equal(t, uint(1), foundSubPlanLinks[0].ChildPlanID)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "失败-计划ID不为0",
|
||||||
|
setupDB: func(db *gorm.DB) {
|
||||||
|
// 无需额外设置
|
||||||
|
},
|
||||||
|
inputPlan: &models.Plan{
|
||||||
|
Model: gorm.Model{ID: 100}, // ID不为0
|
||||||
|
Name: "无效计划",
|
||||||
|
},
|
||||||
|
expectedError: repository.ErrCreateWithNonZeroID,
|
||||||
|
verifyDB: func(t *testing.T, db *gorm.DB, createdPlan *models.Plan) {
|
||||||
|
// 验证数据库中没有创建该计划
|
||||||
|
var count int64
|
||||||
|
db.Model(&models.Plan{}).Where("id = ?", 100).Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "计划不应被创建")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "失败-同时包含任务和子计划",
|
||||||
|
setupDB: func(db *gorm.DB) {
|
||||||
|
createExistingPlan(db, "子计划", models.PlanContentTypeTasks) // 使用有效的 ContentType
|
||||||
|
},
|
||||||
|
inputPlan: &models.Plan{
|
||||||
|
Name: "混合内容计划",
|
||||||
|
ContentType: models.PlanContentTypeTasks, // 声明为任务类型
|
||||||
|
Tasks: []models.Task{{Name: "任务A"}},
|
||||||
|
SubPlans: []models.SubPlan{{ChildPlanID: 1, ChildPlan: &models.Plan{Model: gorm.Model{ID: 1}}}}, // 但也包含子计划
|
||||||
|
},
|
||||||
|
expectedError: repository.ErrMixedContent,
|
||||||
|
verifyDB: func(t *testing.T, db *gorm.DB, createdPlan *models.Plan) {
|
||||||
|
// 验证数据库中没有创建该计划
|
||||||
|
var count int64
|
||||||
|
db.Model(&models.Plan{}).Where("name = ?", "混合内容计划").Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "计划不应被创建")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "失败-子计划ID为0",
|
||||||
|
setupDB: func(db *gorm.DB) {
|
||||||
|
// 无需额外设置
|
||||||
|
},
|
||||||
|
inputPlan: &models.Plan{
|
||||||
|
Name: "无效子计划关联",
|
||||||
|
ContentType: models.PlanContentTypeSubPlans,
|
||||||
|
SubPlans: []models.SubPlan{
|
||||||
|
{ChildPlanID: 0, ChildPlan: &models.Plan{Model: gorm.Model{ID: 0}}}, // 子计划ID为0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: repository.ErrSubPlanIDIsZeroOnCreate,
|
||||||
|
verifyDB: func(t *testing.T, db *gorm.DB, createdPlan *models.Plan) {
|
||||||
|
var count int64
|
||||||
|
db.Model(&models.Plan{}).Where("name = ?", "无效子计划关联").Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "计划不应被创建")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "失败-子计划在数据库中不存在",
|
||||||
|
setupDB: func(db *gorm.DB) {
|
||||||
|
// 不创建ID为999的计划
|
||||||
|
},
|
||||||
|
inputPlan: &models.Plan{
|
||||||
|
Name: "不存在的子计划",
|
||||||
|
ContentType: models.PlanContentTypeSubPlans,
|
||||||
|
SubPlans: []models.SubPlan{
|
||||||
|
{ChildPlanID: 999, ChildPlan: &models.Plan{Model: gorm.Model{ID: 999}}}, // 关联一个不存在的ID
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: repository.ErrNodeDoesNotExist,
|
||||||
|
verifyDB: func(t *testing.T, db *gorm.DB, createdPlan *models.Plan) {
|
||||||
|
var count int64
|
||||||
|
db.Model(&models.Plan{}).Where("name = ?", "不存在的子计划").Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "计划不应被创建")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "失败-任务执行顺序重复",
|
||||||
|
setupDB: func(db *gorm.DB) {
|
||||||
|
// 无需额外设置
|
||||||
|
},
|
||||||
|
inputPlan: &models.Plan{
|
||||||
|
Name: "重复任务顺序计划",
|
||||||
|
ContentType: models.PlanContentTypeTasks,
|
||||||
|
Tasks: []models.Task{
|
||||||
|
{Name: "Task 1", ExecutionOrder: 1},
|
||||||
|
{Name: "Task 2", ExecutionOrder: 1}, // 重复的顺序
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: fmt.Errorf("任务执行顺序重复: %d", 1), // 假设 Create 方法会返回此错误
|
||||||
|
verifyDB: func(t *testing.T, db *gorm.DB, createdPlan *models.Plan) {
|
||||||
|
var count int64
|
||||||
|
db.Model(&models.Plan{}).Where("name = ?", "重复任务顺序计划").Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "重复任务顺序的计划不应被创建")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "失败-子计划执行顺序重复",
|
||||||
|
setupDB: func(db *gorm.DB) {
|
||||||
|
createExistingPlan(db, "子计划A", models.PlanContentTypeTasks)
|
||||||
|
createExistingPlan(db, "子计划B", models.PlanContentTypeTasks)
|
||||||
|
},
|
||||||
|
inputPlan: &models.Plan{
|
||||||
|
Name: "重复子计划顺序计划",
|
||||||
|
ContentType: models.PlanContentTypeSubPlans,
|
||||||
|
SubPlans: []models.SubPlan{
|
||||||
|
{ChildPlanID: 1, ExecutionOrder: 1},
|
||||||
|
{ChildPlanID: 2, ExecutionOrder: 1}, // 重复的顺序
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedError: fmt.Errorf("子计划执行顺序重复: %d", 1), // 假设 Create 方法会返回此错误
|
||||||
|
verifyDB: func(t *testing.T, db *gorm.DB, createdPlan *models.Plan) {
|
||||||
|
var count int64
|
||||||
|
db.Model(&models.Plan{}).Where("name = ?", "重复子计划顺序计划").Count(&count)
|
||||||
|
assert.Equal(t, int64(0), count, "重复子计划顺序的计划不应被创建")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
db := setupTestDB(t)
|
||||||
|
repo := repository.NewGormPlanRepository(db)
|
||||||
|
|
||||||
|
// 准备数据库状态
|
||||||
|
tc.setupDB(db)
|
||||||
|
|
||||||
|
// 执行 Create 操作
|
||||||
|
err := repo.Create(tc.inputPlan)
|
||||||
|
|
||||||
|
// 断言错误
|
||||||
|
if tc.expectedError != nil {
|
||||||
|
assert.Error(t, err)
|
||||||
|
// 使用 Contains 检查错误信息,因为 fmt.Errorf 会创建新的错误实例
|
||||||
|
assert.Contains(t, err.Error(), tc.expectedError.Error())
|
||||||
|
} else {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 验证数据库状态
|
||||||
|
tc.verifyDB(t, db, tc.inputPlan)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user