diff --git a/workflow/dao/flow/flow_segment_result_dao_test.go b/workflow/dao/flow/flow_segment_result_dao_test.go index 5320461..978df16 100644 --- a/workflow/dao/flow/flow_segment_result_dao_test.go +++ b/workflow/dao/flow/flow_segment_result_dao_test.go @@ -7,6 +7,10 @@ import ( "time" "gitea.redpowerfuture.com/red-future/common/beans" + + // 空导入:pgsql 驱动。main.go 里已有,但 go test ./workflow/dao/flow/ 单测包不经 main, + // 不加则报 "cannot find database driver for specified database type pgsql" + _ "github.com/gogf/gf/contrib/drivers/pgsql/v2" ) // TestFlowSegmentResultDao 段结果 DAO 集成测试:Save / ListByNode / DeleteByExecution。 @@ -58,3 +62,52 @@ func TestFlowSegmentResultDao(t *testing.T) { t.Fatalf("删除后应无段结果,实际 %d", len(m)) } } + +// TestFlowSegmentResultDaoResurrect 软删→重存的"复活"路径验证。 +// 实体嵌入 beans.SQLBaseDO(含 deleted_at),GoFrame 将其识别为软删除列: +// DeleteByExecution 实际执行的是 UPDATE ... SET deleted_at=now(),而非物理 DELETE。 +// 本测试验证随后对同一 (execution_id, node_id, segment_index) 的 Save(命中 +// ON CONFLICT ... DO UPDATE)是否会清除 deleted_at,使 ListByNode 再次可见该段。 +// 若不可见,说明 upsert 的 SET 子句不含 deleted_at,复活路径被破坏 → 续跑复用静默失效。 +func TestFlowSegmentResultDaoResurrect(t *testing.T) { + if os.Getenv("AI_AGENT_TEST_DB") == "" { + t.Skip("设置 AI_AGENT_TEST_DB=1 且本地 black_deacon 可用时运行") + } + ctx := context.WithValue(context.Background(), "user", &beans.User{UserName: "unit_test", TenantId: 999999}) + execId := time.Now().UnixMilli() + nodeId := "seg_test_resurrect" + dao := FlowSegmentResultDao + + // 软删即可,物理残留由外部硬清理(docker exec psql DELETE FROM)负责 + t.Cleanup(func() { _ = dao.DeleteByExecution(ctx, execId) }) + + if err := dao.Save(ctx, execId, nodeId, 1, "video_url", "http://host/u1-resurrect.mp4"); err != nil { + t.Fatalf("Save 段1失败: %v", err) + } + if err := dao.Save(ctx, execId, nodeId, 2, "video_url", "http://host/u2-resurrect.mp4"); err != nil { + t.Fatalf("Save 段2失败: %v", err) + } + + // 软删除整条执行 + if err := dao.DeleteByExecution(ctx, execId); err != nil { + t.Fatalf("DeleteByExecution失败: %v", err) + } + + // 重新保存段2(同一 exec/node/idx,不同 URL): + // 若 ON CONFLICT DO UPDATE 的 SET 子句不含 deleted_at,段2 在 ListByNode 中仍不可见 + if err := dao.Save(ctx, execId, nodeId, 2, "video_url", "http://host/u2-resurrect.mp4"); err != nil { + t.Fatalf("Save 段2(软删后重存)失败: %v", err) + } + + m, err := dao.ListByNode(ctx, execId, nodeId) + if err != nil { + t.Fatalf("ListByNode失败: %v", err) + } + // 期望:段2 复活(deleted_at 被 upsert 清除),len(m)==2 且 m[2] 为更新后的 URL + if len(m) != 2 { + t.Fatalf("软删后重存应复活段2(len=2),实际 len=%d: %+v", len(m), m) + } + if m[2].URL != "http://host/u2-resurrect.mp4" { + t.Fatalf("段2 应恢复为更新后的 URL,实际: %+v", m[2]) + } +}