修复: Wave5 审批子系统收尾(R7补 types.ts + R9⑪ failed_node + R8 Request 测试)
- R7补: types.ts event.type string→WorkflowEventType 字面量联合(11 变体 snake_case),静态拦截写错 type - R9⑪: workflow.rs WorkflowFailed failed_node String::new()→状态机取首个 Failed/Cancelled 节点 - R8: human_node 加 request_is_emitted_to_bus 测试,验证 R6(Request 真发到 EventBus) cargo/vue-tsc 0 err / df-nodes 15 test pass
This commit is contained in:
@@ -195,6 +195,40 @@ mod tests {
|
||||
assert_eq!(out.data["comment"], json!("好的"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn request_is_emitted_to_bus() {
|
||||
// B-03b-R8: 验证 HumanNode 真发出 HumanApprovalRequest 到事件总线
|
||||
// (R6 修复前 :41 send 缺 await → Request 未进 channel,此测会超时失败)
|
||||
let bus = EventBus::new();
|
||||
let mut rx = bus.subscribe(); // subscribe 先于 execute send(broadcast 不回放)
|
||||
let ctx = make_ctx(&bus, "exec-1", "node-h", json!({ "timeout_secs": 1 }));
|
||||
let bus_clone = bus.clone();
|
||||
let handle = tokio::spawn(async move { HumanNode.execute(ctx).await });
|
||||
|
||||
// execute send Request 后 rx 应收到
|
||||
let received = tokio::time::timeout(Duration::from_millis(500), rx.recv()).await;
|
||||
assert!(
|
||||
received.is_ok(),
|
||||
"应收到 HumanApprovalRequest(R6 Request 真发出),实际超时"
|
||||
);
|
||||
match received.unwrap().unwrap() {
|
||||
WorkflowEvent::HumanApprovalRequest {
|
||||
execution_id,
|
||||
node_id,
|
||||
title,
|
||||
..
|
||||
} => {
|
||||
assert_eq!(execution_id, "exec-1");
|
||||
assert_eq!(node_id, "node-h");
|
||||
assert_eq!(title, "请确认");
|
||||
}
|
||||
other => panic!("期望 HumanApprovalRequest,收到 {:?}", other),
|
||||
}
|
||||
// 发 Response 让 execute 正常返回(防 task 泄漏)
|
||||
send_response(&bus_clone, "exec-1", "node-h", "同意", None).await;
|
||||
let _ = handle.await;
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn mismatched_execution_id_filtered_then_timeout() {
|
||||
// execution_id 不匹配:Response 被过滤,短超时验证 → Err 超时
|
||||
|
||||
@@ -132,11 +132,20 @@ pub async fn run_workflow(
|
||||
state_registry.lock().await.remove(&exec_id);
|
||||
|
||||
// 执行失败时补发 WorkflowFailed(执行器内部只发 NodeFailed)
|
||||
// failed_node 从状态机取首个失败/取消节点(R9⑪: 原 String::new() 空值)
|
||||
if let Some(error) = error {
|
||||
use df_core::types::NodeStatus;
|
||||
let failed_node = executor
|
||||
.state_machine()
|
||||
.snapshot()
|
||||
.into_iter()
|
||||
.find(|(_, s)| matches!(s, NodeStatus::Failed | NodeStatus::Cancelled))
|
||||
.map(|(id, _)| id)
|
||||
.unwrap_or_default();
|
||||
event_bus
|
||||
.send(WorkflowEvent::WorkflowFailed {
|
||||
error,
|
||||
failed_node: String::new(),
|
||||
failed_node,
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -121,10 +121,16 @@ export interface WorkflowRecord {
|
||||
}
|
||||
|
||||
/** 工作流事件载荷(后端 emit 的结构) */
|
||||
/** 工作流事件类型字面量联合(对应后端 WorkflowEvent serde tag=type rename_all=snake_case,R7收窄防写错 type 字符串) */
|
||||
export type WorkflowEventType =
|
||||
| 'node_started' | 'node_progress' | 'node_output' | 'node_completed' | 'node_failed'
|
||||
| 'workflow_paused' | 'workflow_completed' | 'workflow_failed'
|
||||
| 'human_approval_request' | 'human_approval_response'
|
||||
|
||||
export interface WorkflowEventPayload {
|
||||
execution_id: string
|
||||
event: {
|
||||
type: string
|
||||
type: WorkflowEventType
|
||||
[key: string]: unknown
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user