重构 #4
| @@ -661,6 +661,49 @@ func TestUpdatePlan_Reconciliation(t *testing.T) { | |||||||
| 				assert.Equal(t, uint(11), finalPlan.Tasks[0].ID) | 				assert.Equal(t, uint(11), finalPlan.Tasks[0].ID) | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "任务协调-混沌的同步操作(增删改重排)", | ||||||
|  | 			setupDB: func(db *gorm.DB) uint { | ||||||
|  | 				plan := models.Plan{Model: gorm.Model{ID: 1}, Name: "Plan", ContentType: models.PlanContentTypeTasks} | ||||||
|  | 				db.Create(&plan) | ||||||
|  | 				db.Create(&models.Task{Model: gorm.Model{ID: 10}, PlanID: 1, Name: "Task 1 (Original)", ExecutionOrder: 1}) | ||||||
|  | 				db.Create(&models.Task{Model: gorm.Model{ID: 11}, PlanID: 1, Name: "Task 2 (To Be Deleted)", ExecutionOrder: 2}) | ||||||
|  | 				db.Create(&models.Task{Model: gorm.Model{ID: 12}, PlanID: 1, Name: "Task 3 (Original)", ExecutionOrder: 3}) | ||||||
|  | 				return 1 | ||||||
|  | 			}, | ||||||
|  | 			buildInput: func(db *gorm.DB) *models.Plan { | ||||||
|  | 				return &models.Plan{ | ||||||
|  | 					Model:       gorm.Model{ID: 1}, | ||||||
|  | 					Name:        "Plan", | ||||||
|  | 					ContentType: models.PlanContentTypeTasks, | ||||||
|  | 					Tasks: []models.Task{ | ||||||
|  | 						// T4 (新) -> T3 (不变) -> T1 (更新) | ||||||
|  | 						{Name: "Task 4 (New)", ExecutionOrder: 1}, | ||||||
|  | 						{Model: gorm.Model{ID: 12}, PlanID: 1, Name: "Task 3 (Original)", ExecutionOrder: 2}, | ||||||
|  | 						{Model: gorm.Model{ID: 10}, PlanID: 1, Name: "Task 1 (Updated)", ExecutionOrder: 3}, | ||||||
|  | 					}, | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			verifyDB: func(t *testing.T, db *gorm.DB, rootPlanID uint) { | ||||||
|  | 				var finalPlan models.Plan | ||||||
|  | 				db.Preload("Tasks", func(db *gorm.DB) *gorm.DB { | ||||||
|  | 					return db.Order("execution_order") | ||||||
|  | 				}).First(&finalPlan, rootPlanID) | ||||||
|  |  | ||||||
|  | 				// 验证最终数量 | ||||||
|  | 				assert.Len(t, finalPlan.Tasks, 3) | ||||||
|  |  | ||||||
|  | 				// 验证被删除的 T2 不存在 | ||||||
|  | 				var count int64 | ||||||
|  | 				db.Model(&models.Task{}).Where("id = ?", 11).Count(&count) | ||||||
|  | 				assert.Equal(t, int64(0), count) | ||||||
|  |  | ||||||
|  | 				// 验证顺序和内容 | ||||||
|  | 				assert.Equal(t, "Task 4 (New)", finalPlan.Tasks[0].Name) | ||||||
|  | 				assert.Equal(t, "Task 3 (Original)", finalPlan.Tasks[1].Name) | ||||||
|  | 				assert.Equal(t, "Task 1 (Updated)", finalPlan.Tasks[2].Name) | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "子计划协调-新增一个关联", | 			name: "子计划协调-新增一个关联", | ||||||
| 			setupDB: func(db *gorm.DB) uint { | 			setupDB: func(db *gorm.DB) uint { | ||||||
| @@ -736,6 +779,32 @@ func TestUpdatePlan_Reconciliation(t *testing.T) { | |||||||
| 				assert.Equal(t, int64(1), linkCount, "新关联应被创建") | 				assert.Equal(t, int64(1), linkCount, "新关联应被创建") | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "类型转换-从子计划切换到任务", | ||||||
|  | 			setupDB: func(db *gorm.DB) uint { | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 1}, Name: "Plan", ContentType: models.PlanContentTypeSubPlans}) | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 10}, Name: "Old Child"}) | ||||||
|  | 				db.Create(&models.SubPlan{ParentPlanID: 1, ChildPlanID: 10}) | ||||||
|  | 				return 1 | ||||||
|  | 			}, | ||||||
|  | 			buildInput: func(db *gorm.DB) *models.Plan { | ||||||
|  | 				return &models.Plan{ | ||||||
|  | 					Model:       gorm.Model{ID: 1}, | ||||||
|  | 					Name:        "Plan", | ||||||
|  | 					ContentType: models.PlanContentTypeTasks, // 类型变更 | ||||||
|  | 					Tasks:       []models.Task{{Name: "New Task"}}, | ||||||
|  | 				} | ||||||
|  | 			}, | ||||||
|  | 			verifyDB: func(t *testing.T, db *gorm.DB, rootPlanID uint) { | ||||||
|  | 				var linkCount int64 | ||||||
|  | 				db.Model(&models.SubPlan{}).Where("parent_plan_id = ?", rootPlanID).Count(&linkCount) | ||||||
|  | 				assert.Equal(t, int64(0), linkCount, "旧的子计划关联应被清理") | ||||||
|  |  | ||||||
|  | 				var taskCount int64 | ||||||
|  | 				db.Model(&models.Task{}).Where("plan_id = ?", rootPlanID).Count(&taskCount) | ||||||
|  | 				assert.Equal(t, int64(1), taskCount, "新任务应被创建") | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			name: "递归更新-深层节点的变更", | 			name: "递归更新-深层节点的变更", | ||||||
| 			setupDB: func(db *gorm.DB) uint { | 			setupDB: func(db *gorm.DB) uint { | ||||||
| @@ -776,6 +845,166 @@ func TestUpdatePlan_Reconciliation(t *testing.T) { | |||||||
| 				assert.Equal(t, "C Updated", finalC.Name) | 				assert.Equal(t, "C Updated", finalC.Name) | ||||||
| 			}, | 			}, | ||||||
| 		}, | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "递归更新-深层节点的类型转换(C从SubPlans变为Tasks)", | ||||||
|  | 			setupDB: func(db *gorm.DB) uint { | ||||||
|  | 				// 初始状态: A -> B -> C -> D | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 1}, Name: "A", ContentType: models.PlanContentTypeSubPlans}) | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 2}, Name: "B", ContentType: models.PlanContentTypeSubPlans}) | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 3}, Name: "C", ContentType: models.PlanContentTypeSubPlans}) // C的初始类型 | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 4}, Name: "D"}) | ||||||
|  | 				db.Create(&models.SubPlan{ParentPlanID: 1, ChildPlanID: 2}) | ||||||
|  | 				db.Create(&models.SubPlan{ParentPlanID: 2, ChildPlanID: 3}) | ||||||
|  | 				db.Create(&models.SubPlan{Model: gorm.Model{ID: 99}, ParentPlanID: 3, ChildPlanID: 4}) // C->D 的关联 | ||||||
|  | 				return 1 | ||||||
|  | 			}, | ||||||
|  | 			buildInput: func(db *gorm.DB) *models.Plan { | ||||||
|  | 				// 更新操作: C的类型变为Tasks,并增加一个新Task | ||||||
|  | 				planC := &models.Plan{ | ||||||
|  | 					Model:       gorm.Model{ID: 3}, | ||||||
|  | 					Name:        "C", | ||||||
|  | 					ContentType: models.PlanContentTypeTasks, // 类型变更 | ||||||
|  | 					Tasks:       []models.Task{{Name: "C's New Task"}}, | ||||||
|  | 				} | ||||||
|  | 				planB := &models.Plan{ | ||||||
|  | 					Model:       gorm.Model{ID: 2}, | ||||||
|  | 					Name:        "B", | ||||||
|  | 					ContentType: models.PlanContentTypeSubPlans, | ||||||
|  | 					SubPlans:    []models.SubPlan{{ChildPlanID: 3, ChildPlan: planC}}, | ||||||
|  | 				} | ||||||
|  | 				planA := &models.Plan{ | ||||||
|  | 					Model:       gorm.Model{ID: 1}, | ||||||
|  | 					Name:        "A", | ||||||
|  | 					ContentType: models.PlanContentTypeSubPlans, | ||||||
|  | 					SubPlans:    []models.SubPlan{{ChildPlanID: 2, ChildPlan: planB}}, | ||||||
|  | 				} | ||||||
|  | 				return planA | ||||||
|  | 			}, | ||||||
|  | 			verifyDB: func(t *testing.T, db *gorm.DB, rootPlanID uint) { | ||||||
|  | 				// 1. 验证 C->D 的旧关联已被删除 | ||||||
|  | 				var linkCount int64 | ||||||
|  | 				db.Model(&models.SubPlan{}).Where("id = ?", 99).Count(&linkCount) | ||||||
|  | 				assert.Equal(t, int64(0), linkCount, "C的旧子计划关联应被清理") | ||||||
|  |  | ||||||
|  | 				// 2. 验证 C 的新Task已被创建 | ||||||
|  | 				var task models.Task | ||||||
|  | 				err := db.Where("plan_id = ?", 3).First(&task).Error | ||||||
|  | 				assert.NoError(t, err, "C的新任务应该被创建") | ||||||
|  | 				assert.Equal(t, "C's New Task", task.Name) | ||||||
|  |  | ||||||
|  | 				// 3. 验证 D 计划本身依然存在 | ||||||
|  | 				var planDCount int64 | ||||||
|  | 				db.Model(&models.Plan{}).Where("id = ?", 4).Count(&planDCount) | ||||||
|  | 				assert.Equal(t, int64(1), planDCount, "计划D本身不应被删除") | ||||||
|  | 			}, | ||||||
|  | 		}, { | ||||||
|  | 			name: "递归更新-中间层分支替换(A->B变为A->D)", | ||||||
|  | 			setupDB: func(db *gorm.DB) uint { | ||||||
|  | 				// 初始状态: A -> B -> C | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 1}, Name: "A", ContentType: models.PlanContentTypeSubPlans}) | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 2}, Name: "B", ContentType: models.PlanContentTypeSubPlans}) | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 3}, Name: "C"}) | ||||||
|  | 				db.Create(&models.SubPlan{Model: gorm.Model{ID: 101}, ParentPlanID: 1, ChildPlanID: 2}) // A->B | ||||||
|  | 				db.Create(&models.SubPlan{ParentPlanID: 2, ChildPlanID: 3})                             // B->C | ||||||
|  |  | ||||||
|  | 				// 准备用于替换的分支: D -> E | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 4}, Name: "D", ContentType: models.PlanContentTypeSubPlans}) | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 5}, Name: "E"}) | ||||||
|  | 				db.Create(&models.SubPlan{ParentPlanID: 4, ChildPlanID: 5}) // D->E | ||||||
|  | 				return 1 | ||||||
|  | 			}, | ||||||
|  | 			buildInput: func(db *gorm.DB) *models.Plan { | ||||||
|  | 				// 更新操作: A的子计划从 B 替换为 D | ||||||
|  | 				planE := &models.Plan{Model: gorm.Model{ID: 5}, Name: "E Updated"} // 同时更新深层节点 | ||||||
|  | 				planD := &models.Plan{ | ||||||
|  | 					Model:       gorm.Model{ID: 4}, | ||||||
|  | 					Name:        "D", | ||||||
|  | 					ContentType: models.PlanContentTypeSubPlans, | ||||||
|  | 					SubPlans:    []models.SubPlan{{ChildPlanID: 5, ChildPlan: planE}}, | ||||||
|  | 				} | ||||||
|  | 				planA := &models.Plan{ | ||||||
|  | 					Model:       gorm.Model{ID: 1}, | ||||||
|  | 					Name:        "A", | ||||||
|  | 					ContentType: models.PlanContentTypeSubPlans, | ||||||
|  | 					SubPlans:    []models.SubPlan{{ChildPlanID: 4, ChildPlan: planD}}, // 新关联 A->D | ||||||
|  | 				} | ||||||
|  | 				return planA | ||||||
|  | 			}, | ||||||
|  | 			verifyDB: func(t *testing.T, db *gorm.DB, rootPlanID uint) { | ||||||
|  | 				// 1. 验证 A->B 的旧关联已被删除 | ||||||
|  | 				var linkCount int64 | ||||||
|  | 				db.Model(&models.SubPlan{}).Where("id = ?", 101).Count(&linkCount) | ||||||
|  | 				assert.Equal(t, int64(0), linkCount, "A->B 的旧关联应被删除") | ||||||
|  |  | ||||||
|  | 				// 2. 验证 A->D 的新关联已创建 | ||||||
|  | 				var newLink models.SubPlan | ||||||
|  | 				err := db.Where("parent_plan_id = ? AND child_plan_id = ?", 1, 4).First(&newLink).Error | ||||||
|  | 				assert.NoError(t, err, "A->D 的新关联应被创建") | ||||||
|  |  | ||||||
|  | 				// 3. 验证 B, C, D, E 计划本身都依然存在 | ||||||
|  | 				var planCount int64 | ||||||
|  | 				db.Model(&models.Plan{}).Where("id IN ?", []uint{2, 3, 4, 5}).Count(&planCount) | ||||||
|  | 				assert.Equal(t, int64(4), planCount, "所有被引用或解引用的计划本身都不应被删除") | ||||||
|  |  | ||||||
|  | 				// 4. 验证对新分支深层节点的递归更新已生效 | ||||||
|  | 				var finalE models.Plan | ||||||
|  | 				db.First(&finalE, 5) | ||||||
|  | 				assert.Equal(t, "E Updated", finalE.Name) | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			name: "递归更新-菱形依赖下的冲突更新", | ||||||
|  | 			setupDB: func(db *gorm.DB) uint { | ||||||
|  | 				// 初始状态: A -> B -> D, A -> C -> D | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 1}, Name: "A", ContentType: models.PlanContentTypeSubPlans}) | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 2}, Name: "B", ContentType: models.PlanContentTypeSubPlans}) | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 3}, Name: "C", ContentType: models.PlanContentTypeSubPlans}) | ||||||
|  | 				db.Create(&models.Plan{Model: gorm.Model{ID: 4}, Name: "D (Original)"}) // D的初始名字 | ||||||
|  | 				// 创建关联 | ||||||
|  | 				db.Create(&models.SubPlan{ParentPlanID: 1, ChildPlanID: 2, ExecutionOrder: 1}) // A->B | ||||||
|  | 				db.Create(&models.SubPlan{ParentPlanID: 1, ChildPlanID: 3, ExecutionOrder: 2}) // A->C | ||||||
|  | 				db.Create(&models.SubPlan{ParentPlanID: 2, ChildPlanID: 4})                    // B->D | ||||||
|  | 				db.Create(&models.SubPlan{ParentPlanID: 3, ChildPlanID: 4})                    // C->D | ||||||
|  | 				return 1 | ||||||
|  | 			}, | ||||||
|  | 			buildInput: func(db *gorm.DB) *models.Plan { | ||||||
|  | 				// 在一次调用中,通过不同路径对 D 进行不同的更新 | ||||||
|  | 				planD_fromB := &models.Plan{Model: gorm.Model{ID: 4}, Name: "D (Updated from B)"} | ||||||
|  | 				planD_fromC := &models.Plan{Model: gorm.Model{ID: 4}, Name: "D (Updated from C)"} | ||||||
|  |  | ||||||
|  | 				planB := &models.Plan{ | ||||||
|  | 					Model:       gorm.Model{ID: 2}, | ||||||
|  | 					ContentType: models.PlanContentTypeSubPlans, | ||||||
|  | 					SubPlans:    []models.SubPlan{{ChildPlanID: 4, ChildPlan: planD_fromB}}, | ||||||
|  | 				} | ||||||
|  | 				planC := &models.Plan{ | ||||||
|  | 					Model:       gorm.Model{ID: 3}, | ||||||
|  | 					ContentType: models.PlanContentTypeSubPlans, | ||||||
|  | 					SubPlans:    []models.SubPlan{{ChildPlanID: 4, ChildPlan: planD_fromC}}, | ||||||
|  | 				} | ||||||
|  | 				planA := &models.Plan{ | ||||||
|  | 					Model:       gorm.Model{ID: 1}, | ||||||
|  | 					ContentType: models.PlanContentTypeSubPlans, | ||||||
|  | 					SubPlans: []models.SubPlan{ | ||||||
|  | 						{ChildPlanID: 2, ChildPlan: planB, ExecutionOrder: 1}, | ||||||
|  | 						{ChildPlanID: 3, ChildPlan: planC, ExecutionOrder: 2}, // C 在 B 之后 | ||||||
|  | 					}, | ||||||
|  | 				} | ||||||
|  | 				return planA | ||||||
|  | 			}, | ||||||
|  | 			verifyDB: func(t *testing.T, db *gorm.DB, rootPlanID uint) { | ||||||
|  | 				// 验证:D 的最终名字应该符合“最后一次更新获胜”的原则 | ||||||
|  | 				// 由于 planC 在 planB 之后被处理,D 的名字应该是 "D (Updated from C)" | ||||||
|  | 				var finalD models.Plan | ||||||
|  | 				db.First(&finalD, 4) | ||||||
|  | 				assert.Equal(t, "D (Updated from C)", finalD.Name, "共享下游节点的更新应以后一次执行为准") | ||||||
|  |  | ||||||
|  | 				// 确保所有关联依然存在 | ||||||
|  | 				var linkCount int64 | ||||||
|  | 				db.Model(&models.SubPlan{}).Where("child_plan_id = ?", 4).Count(&linkCount) | ||||||
|  | 				assert.Equal(t, int64(2), linkCount, "D 的两个上游关联都应继续存在") | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	for _, tc := range testCases { | 	for _, tc := range testCases { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user