@feltdb/core 0.4.11 → 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/commands.js +5 -2
- package/dist/cli/index.js +1 -1
- package/dist/create/cli.js +16 -1
- package/dist/create/create.js +30 -16
- package/dist/create/docker-compose-generator.js +48 -9
- package/dist/create/package-versions.js +1 -1
- package/dist/create/server-source/Cargo.lock +2238 -0
- package/dist/create/server-source/Cargo.toml +7 -0
- package/dist/create/server-source/crates/feltdb/Cargo.lock +175 -0
- package/dist/create/server-source/crates/feltdb/Cargo.toml +79 -0
- package/dist/create/server-source/crates/feltdb/benches/baselines/gate-13-redux.json +370 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_baseline.rs +589 -0
- package/dist/create/server-source/crates/feltdb/benches/gate13_phase_7_1_release_economics.rs +259 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_redux.rs +446 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_13_regression_runner.rs +272 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_concurrent_writer_scaling.rs +378 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_production_admission_revalidation.rs +414 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc2_admission_contract.rs +486 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_rc_root_cause.rs +273 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync1_queued_prototype.rs +587 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14a_sync_economics.rs +513 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14b_causal_backlog_scaling.rs +395 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_contract_test.rs +469 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14c_replication_scaling.rs +409 -0
- package/dist/create/server-source/crates/feltdb/benches/gate_14d_combined_dimension_scaling.rs +627 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_2_optimization_benchmark.rs +383 -0
- package/dist/create/server-source/crates/feltdb/benches/phase_7_1_3_crossover_analysis.rs +298 -0
- package/dist/create/server-source/crates/feltdb/src/acceptance_tests.rs +1698 -0
- package/dist/create/server-source/crates/feltdb/src/acquisition.rs +286 -0
- package/dist/create/server-source/crates/feltdb/src/admission.rs +192 -0
- package/dist/create/server-source/crates/feltdb/src/admission_contract_tests.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/adversarial_transport.rs +566 -0
- package/dist/create/server-source/crates/feltdb/src/analytics.rs +475 -0
- package/dist/create/server-source/crates/feltdb/src/application.rs +2244 -0
- package/dist/create/server-source/crates/feltdb/src/application_runtime.rs +1070 -0
- package/dist/create/server-source/crates/feltdb/src/authorization.rs +1030 -0
- package/dist/create/server-source/crates/feltdb/src/bin/feltdb_node.rs +266 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/mod.rs +8 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/search.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/capabilities/vector.rs +482 -0
- package/dist/create/server-source/crates/feltdb/src/capability.rs +903 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_diagnostics.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/cardinality_endpoint.rs +78 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier.rs +2214 -0
- package/dist/create/server-source/crates/feltdb/src/causal_dependency_barrier_phase_7_1.rs +194 -0
- package/dist/create/server-source/crates/feltdb/src/concurrency_fuzzing.rs +427 -0
- package/dist/create/server-source/crates/feltdb/src/consistency_contract.rs +453 -0
- package/dist/create/server-source/crates/feltdb/src/content_distribution.rs +465 -0
- package/dist/create/server-source/crates/feltdb/src/convergence.rs +618 -0
- package/dist/create/server-source/crates/feltdb/src/crash_atomic_boundary.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/crash_injection.rs +380 -0
- package/dist/create/server-source/crates/feltdb/src/crash_recovery_tests.rs +362 -0
- package/dist/create/server-source/crates/feltdb/src/cron.rs +294 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_indexing.rs +474 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_tests.rs +1003 -0
- package/dist/create/server-source/crates/feltdb/src/distributed_transactions.rs +536 -0
- package/dist/create/server-source/crates/feltdb/src/durability_guarantees.rs +364 -0
- package/dist/create/server-source/crates/feltdb/src/durable_dedup_set.rs +235 -0
- package/dist/create/server-source/crates/feltdb/src/durable_operation_log.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/durable_sync.rs +316 -0
- package/dist/create/server-source/crates/feltdb/src/execution.rs +426 -0
- package/dist/create/server-source/crates/feltdb/src/in_process_transport.rs +219 -0
- package/dist/create/server-source/crates/feltdb/src/indexing.rs +779 -0
- package/dist/create/server-source/crates/feltdb/src/lib.rs +2838 -0
- package/dist/create/server-source/crates/feltdb/src/materialization.rs +184 -0
- package/dist/create/server-source/crates/feltdb/src/metrics.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/multi_node_convergence.rs +311 -0
- package/dist/create/server-source/crates/feltdb/src/observability.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/operation.rs +251 -0
- package/dist/create/server-source/crates/feltdb/src/operation_algebra.rs +438 -0
- package/dist/create/server-source/crates/feltdb/src/operation_log.rs +344 -0
- package/dist/create/server-source/crates/feltdb/src/partition_reconciliation.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/peer_registry.rs +166 -0
- package/dist/create/server-source/crates/feltdb/src/permutation_scheduler.rs +261 -0
- package/dist/create/server-source/crates/feltdb/src/persistence_reality.rs +560 -0
- package/dist/create/server-source/crates/feltdb/src/phase1b_acceptance.rs +3226 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c1_acceptance.rs +201 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c2_acceptance.rs +263 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c3_acceptance.rs +484 -0
- package/dist/create/server-source/crates/feltdb/src/phase1c_atomicity_proof.rs +216 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_integration.rs +281 -0
- package/dist/create/server-source/crates/feltdb/src/phase5_scenarios.rs +323 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_adversarial_scenarios.rs +573 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_convergence_validator.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/phase6_persistence.rs +418 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_real_tcp.rs +381 -0
- package/dist/create/server-source/crates/feltdb/src/phase_1c_three_node.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2a_failures.rs +334 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2b_network.rs +306 -0
- package/dist/create/server-source/crates/feltdb/src/phase_2c_cascading.rs +355 -0
- package/dist/create/server-source/crates/feltdb/src/phase_3_durability.rs +395 -0
- package/dist/create/server-source/crates/feltdb/src/phase_4_baseline.rs +346 -0
- package/dist/create/server-source/crates/feltdb/src/phase_5_soak.rs +430 -0
- package/dist/create/server-source/crates/feltdb/src/production_api.rs +400 -0
- package/dist/create/server-source/crates/feltdb/src/provenance.rs +207 -0
- package/dist/create/server-source/crates/feltdb/src/query_performance.rs +217 -0
- package/dist/create/server-source/crates/feltdb/src/references.rs +404 -0
- package/dist/create/server-source/crates/feltdb/src/replay_fuzzing.rs +401 -0
- package/dist/create/server-source/crates/feltdb/src/replication_manager.rs +160 -0
- package/dist/create/server-source/crates/feltdb/src/replication_protocol.rs +132 -0
- package/dist/create/server-source/crates/feltdb/src/routing.rs +409 -0
- package/dist/create/server-source/crates/feltdb/src/sharding.rs +523 -0
- package/dist/create/server-source/crates/feltdb/src/state_contract.rs +3118 -0
- package/dist/create/server-source/crates/feltdb/src/state_hash.rs +291 -0
- package/dist/create/server-source/crates/feltdb/src/state_transition_store.rs +376 -0
- package/dist/create/server-source/crates/feltdb/src/storage.rs +267 -0
- package/dist/create/server-source/crates/feltdb/src/submission.rs +477 -0
- package/dist/create/server-source/crates/feltdb/src/sync.rs +483 -0
- package/dist/create/server-source/crates/feltdb/src/sync_contract.rs +822 -0
- package/dist/create/server-source/crates/feltdb/src/tcp_transport.rs +366 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_api.rs +473 -0
- package/dist/create/server-source/crates/feltdb/src/transaction_invariants.rs +949 -0
- package/dist/create/server-source/crates/feltdb/src/transactions.rs +646 -0
- package/dist/create/server-source/crates/feltdb/src/trigger.rs +390 -0
- package/dist/create/server-source/crates/feltdb/src/worker_mesh.rs +928 -0
- package/dist/create/server-source/crates/feltdb/src/workflow.rs +713 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_acceptance_tests.rs +510 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_integration.rs +354 -0
- package/dist/create/server-source/crates/feltdb/src/workflow_runtime.rs +594 -0
- package/dist/create/server-source/crates/feltdb/src/workload.rs +1310 -0
- package/dist/create/server-source/crates/feltdb-server/Cargo.toml +23 -0
- package/dist/create/server-source/crates/feltdb-server/README.md +79 -0
- package/dist/create/server-source/crates/feltdb-server/src/app_state.rs +73 -0
- package/dist/create/server-source/crates/feltdb-server/src/application_contract.rs +425 -0
- package/dist/create/server-source/crates/feltdb-server/src/artifacts.rs +449 -0
- package/dist/create/server-source/crates/feltdb-server/src/audit.rs +59 -0
- package/dist/create/server-source/crates/feltdb-server/src/auth.rs +308 -0
- package/dist/create/server-source/crates/feltdb-server/src/authorization.rs +228 -0
- package/dist/create/server-source/crates/feltdb-server/src/backup.rs +416 -0
- package/dist/create/server-source/crates/feltdb-server/src/causal.rs +218 -0
- package/dist/create/server-source/crates/feltdb-server/src/certification.rs +223 -0
- package/dist/create/server-source/crates/feltdb-server/src/clock.rs +132 -0
- package/dist/create/server-source/crates/feltdb-server/src/cluster.rs +165 -0
- package/dist/create/server-source/crates/feltdb-server/src/connections.rs +1044 -0
- package/dist/create/server-source/crates/feltdb-server/src/content.rs +111 -0
- package/dist/create/server-source/crates/feltdb-server/src/identity.rs +250 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_management.rs +78 -0
- package/dist/create/server-source/crates/feltdb-server/src/key_provider.rs +247 -0
- package/dist/create/server-source/crates/feltdb-server/src/leases.rs +123 -0
- package/dist/create/server-source/crates/feltdb-server/src/lib.rs +25 -0
- package/dist/create/server-source/crates/feltdb-server/src/main.rs +8715 -0
- package/dist/create/server-source/crates/feltdb-server/src/metrics.rs +97 -0
- package/dist/create/server-source/crates/feltdb-server/src/portable_bundle.rs +350 -0
- package/dist/create/server-source/crates/feltdb-server/src/principals.rs +510 -0
- package/dist/create/server-source/crates/feltdb-server/src/providers.rs +269 -0
- package/dist/create/server-source/crates/feltdb-server/src/releases.rs +2563 -0
- package/dist/create/server-source/crates/feltdb-server/src/sessions.rs +156 -0
- package/dist/create/server-source/crates/feltdb-server/src/tenancy.rs +1097 -0
- package/dist/create/server-source/crates/feltdb-server/src/versions.rs +264 -0
- package/dist/create/server-source/crates/feltdb-wasm/Cargo.toml +31 -0
- package/dist/create/server-source/crates/feltdb-wasm/src/lib.rs +1086 -0
- package/dist/create/server-source/crates/feltdb-wasm/test.db +0 -0
- package/dist/flowspec.d.ts +2 -0
- package/dist/flowspec.d.ts.map +1 -1
- package/dist/flowspec.js +28 -4
- package/dist/state-contract.d.ts +7 -1
- package/dist/state-contract.d.ts.map +1 -1
- package/dist/studio/components/ApplicationDesigner.d.ts.map +1 -1
- package/dist/studio/components/index.js +1 -1
- package/dist/studio/{components-q43NSTTH.js → components-bHTARBin.js} +160 -89
- package/dist/studio/index.js +31 -28
- package/dist/studio-app/assets/{index-DZpBoVMp.js → index-BqKquLuU.js} +8 -8
- package/dist/studio-app/index.html +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
/// Workflow acceptance tests demonstrating the distributed workflow runtime
|
|
2
|
+
///
|
|
3
|
+
/// Tests comprehensive workflows across multiple peers with various scenarios:
|
|
4
|
+
/// - Linear workflows with dependencies
|
|
5
|
+
/// - Parallel workflows with joins
|
|
6
|
+
/// - Conditional workflows
|
|
7
|
+
/// - Workflow mobility (continue on different peer)
|
|
8
|
+
/// - Failure and recovery
|
|
9
|
+
/// - Provenance tracking
|
|
10
|
+
use crate::{FlowRef, WorkflowGraph, WorkflowNode, WorkflowRef, WorkflowRuntime};
|
|
11
|
+
|
|
12
|
+
#[cfg(test)]
|
|
13
|
+
mod tests {
|
|
14
|
+
use super::*;
|
|
15
|
+
|
|
16
|
+
/// Test 1: Simple linear workflow
|
|
17
|
+
/// Document → Extract → Embed → Done
|
|
18
|
+
#[test]
|
|
19
|
+
fn test_simple_linear_workflow() {
|
|
20
|
+
let mut runtime = WorkflowRuntime::new();
|
|
21
|
+
|
|
22
|
+
// Define workflow
|
|
23
|
+
let workflow_ref = WorkflowRef::new("workflow", "document-processing", 1);
|
|
24
|
+
let graph = WorkflowGraph::new(workflow_ref.clone())
|
|
25
|
+
.add_node(WorkflowNode::new("extract", "extract-text"))
|
|
26
|
+
.add_node(WorkflowNode::new("embed", "embedding").with_input("extract"))
|
|
27
|
+
.add_node(WorkflowNode::new("save", "save-results").with_input("embed"))
|
|
28
|
+
.add_edge("extract", "embed")
|
|
29
|
+
.add_edge("embed", "save");
|
|
30
|
+
|
|
31
|
+
runtime
|
|
32
|
+
.register_workflow(graph)
|
|
33
|
+
.expect("Failed to register workflow");
|
|
34
|
+
|
|
35
|
+
// Create instance
|
|
36
|
+
let document = FlowRef::new("documents", "doc-1");
|
|
37
|
+
let instance_id = runtime
|
|
38
|
+
.create_instance(workflow_ref.clone(), "workflow-1", vec![document.clone()])
|
|
39
|
+
.expect("Failed to create instance");
|
|
40
|
+
|
|
41
|
+
// Start workflow
|
|
42
|
+
runtime
|
|
43
|
+
.start_instance(&instance_id)
|
|
44
|
+
.expect("Failed to start");
|
|
45
|
+
|
|
46
|
+
// Verify entry point (extract) is ready
|
|
47
|
+
let ready = runtime.ready_steps(&instance_id);
|
|
48
|
+
assert!(ready.contains(&"extract".to_string()));
|
|
49
|
+
assert!(!ready.contains(&"embed".to_string()));
|
|
50
|
+
|
|
51
|
+
// Execute extract step
|
|
52
|
+
runtime
|
|
53
|
+
.claim_step(&instance_id, "extract", "peer-a")
|
|
54
|
+
.expect("Failed to claim");
|
|
55
|
+
runtime
|
|
56
|
+
.step_completed(&instance_id, "extract", FlowRef::new("texts", "text-1"))
|
|
57
|
+
.expect("Failed to complete");
|
|
58
|
+
|
|
59
|
+
// Verify embed becomes ready
|
|
60
|
+
let ready = runtime.ready_steps(&instance_id);
|
|
61
|
+
assert!(ready.contains(&"embed".to_string()));
|
|
62
|
+
|
|
63
|
+
// Execute embed step
|
|
64
|
+
runtime
|
|
65
|
+
.claim_step(&instance_id, "embed", "peer-b")
|
|
66
|
+
.expect("Failed to claim");
|
|
67
|
+
runtime
|
|
68
|
+
.step_completed(&instance_id, "embed", FlowRef::new("embeddings", "embed-1"))
|
|
69
|
+
.expect("Failed to complete");
|
|
70
|
+
|
|
71
|
+
// Verify save becomes ready
|
|
72
|
+
let ready = runtime.ready_steps(&instance_id);
|
|
73
|
+
assert!(ready.contains(&"save".to_string()));
|
|
74
|
+
|
|
75
|
+
// Execute save step
|
|
76
|
+
runtime
|
|
77
|
+
.claim_step(&instance_id, "save", "peer-c")
|
|
78
|
+
.expect("Failed to claim");
|
|
79
|
+
runtime
|
|
80
|
+
.step_completed(&instance_id, "save", FlowRef::new("results", "result-1"))
|
|
81
|
+
.expect("Failed to complete");
|
|
82
|
+
|
|
83
|
+
// Verify workflow is completed
|
|
84
|
+
let instance = runtime.get_instance(&instance_id).unwrap();
|
|
85
|
+
assert_eq!(instance.state, crate::WorkflowState::Completed);
|
|
86
|
+
|
|
87
|
+
// Check operations log
|
|
88
|
+
let ops = runtime.operations_log();
|
|
89
|
+
assert!(!ops.is_empty());
|
|
90
|
+
println!("Generated {} workflow operations", ops.len());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// Test 2: Parallel workflow with join
|
|
94
|
+
/// Document → Extract → (Embed || Classify) → Join → Summarize
|
|
95
|
+
#[test]
|
|
96
|
+
fn test_parallel_workflow_with_join() {
|
|
97
|
+
let mut runtime = WorkflowRuntime::new();
|
|
98
|
+
|
|
99
|
+
let workflow_ref = WorkflowRef::new("workflow", "parallel-processing", 1);
|
|
100
|
+
let graph = WorkflowGraph::new(workflow_ref.clone())
|
|
101
|
+
.add_node(WorkflowNode::new("extract", "extract-text"))
|
|
102
|
+
.add_node(WorkflowNode::new("embed", "embedding").with_input("extract"))
|
|
103
|
+
.add_node(WorkflowNode::new("classify", "classifier").with_input("extract"))
|
|
104
|
+
.add_node(
|
|
105
|
+
WorkflowNode::new("join", "merge-results")
|
|
106
|
+
.with_input("embed")
|
|
107
|
+
.with_input("classify"),
|
|
108
|
+
)
|
|
109
|
+
.add_node(WorkflowNode::new("summarize", "summarization").with_input("join"))
|
|
110
|
+
.add_edge("extract", "embed")
|
|
111
|
+
.add_edge("extract", "classify")
|
|
112
|
+
.add_edge("embed", "join")
|
|
113
|
+
.add_edge("classify", "join")
|
|
114
|
+
.add_edge("join", "summarize");
|
|
115
|
+
|
|
116
|
+
runtime
|
|
117
|
+
.register_workflow(graph)
|
|
118
|
+
.expect("Failed to register workflow");
|
|
119
|
+
|
|
120
|
+
let instance_id = runtime
|
|
121
|
+
.create_instance(
|
|
122
|
+
workflow_ref.clone(),
|
|
123
|
+
"workflow-2",
|
|
124
|
+
vec![FlowRef::new("documents", "doc-1")],
|
|
125
|
+
)
|
|
126
|
+
.expect("Failed to create instance");
|
|
127
|
+
|
|
128
|
+
runtime
|
|
129
|
+
.start_instance(&instance_id)
|
|
130
|
+
.expect("Failed to start");
|
|
131
|
+
|
|
132
|
+
// Extract completes
|
|
133
|
+
runtime
|
|
134
|
+
.claim_step(&instance_id, "extract", "peer-a")
|
|
135
|
+
.expect("Failed to claim");
|
|
136
|
+
runtime
|
|
137
|
+
.step_completed(&instance_id, "extract", FlowRef::new("texts", "text-1"))
|
|
138
|
+
.expect("Failed to complete");
|
|
139
|
+
|
|
140
|
+
// Both embed and classify should be ready
|
|
141
|
+
let ready = runtime.ready_steps(&instance_id);
|
|
142
|
+
assert!(ready.contains(&"embed".to_string()));
|
|
143
|
+
assert!(ready.contains(&"classify".to_string()));
|
|
144
|
+
assert!(!ready.contains(&"join".to_string()));
|
|
145
|
+
|
|
146
|
+
// Complete embed
|
|
147
|
+
runtime
|
|
148
|
+
.claim_step(&instance_id, "embed", "peer-b")
|
|
149
|
+
.expect("Failed to claim");
|
|
150
|
+
runtime
|
|
151
|
+
.step_completed(&instance_id, "embed", FlowRef::new("embeddings", "embed-1"))
|
|
152
|
+
.expect("Failed to complete");
|
|
153
|
+
|
|
154
|
+
// Complete classify
|
|
155
|
+
runtime
|
|
156
|
+
.claim_step(&instance_id, "classify", "peer-c")
|
|
157
|
+
.expect("Failed to claim");
|
|
158
|
+
runtime
|
|
159
|
+
.step_completed(&instance_id, "classify", FlowRef::new("classes", "class-1"))
|
|
160
|
+
.expect("Failed to complete");
|
|
161
|
+
|
|
162
|
+
// Now join should be ready
|
|
163
|
+
let ready = runtime.ready_steps(&instance_id);
|
|
164
|
+
assert!(ready.contains(&"join".to_string()));
|
|
165
|
+
|
|
166
|
+
// Complete join and summarize
|
|
167
|
+
runtime
|
|
168
|
+
.claim_step(&instance_id, "join", "peer-d")
|
|
169
|
+
.expect("Failed to claim");
|
|
170
|
+
runtime
|
|
171
|
+
.step_completed(&instance_id, "join", FlowRef::new("merged", "merged-1"))
|
|
172
|
+
.expect("Failed to complete");
|
|
173
|
+
|
|
174
|
+
runtime
|
|
175
|
+
.claim_step(&instance_id, "summarize", "peer-e")
|
|
176
|
+
.expect("Failed to claim");
|
|
177
|
+
runtime
|
|
178
|
+
.step_completed(
|
|
179
|
+
&instance_id,
|
|
180
|
+
"summarize",
|
|
181
|
+
FlowRef::new("summary", "summary-1"),
|
|
182
|
+
)
|
|
183
|
+
.expect("Failed to complete");
|
|
184
|
+
|
|
185
|
+
// Verify workflow is completed
|
|
186
|
+
let instance = runtime.get_instance(&instance_id).unwrap();
|
|
187
|
+
assert_eq!(instance.state, crate::WorkflowState::Completed);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/// Test 3: Workflow with blocking and approval
|
|
191
|
+
/// Document → Review (blocked awaiting approval) → Process
|
|
192
|
+
#[test]
|
|
193
|
+
fn test_workflow_with_human_intervention() {
|
|
194
|
+
let mut runtime = WorkflowRuntime::new();
|
|
195
|
+
|
|
196
|
+
let workflow_ref = WorkflowRef::new("workflow", "approval-required", 1);
|
|
197
|
+
let graph = WorkflowGraph::new(workflow_ref.clone())
|
|
198
|
+
.add_node(WorkflowNode::new("extract", "extract-text"))
|
|
199
|
+
.add_node(WorkflowNode::new("review", "manual-review").with_input("extract"))
|
|
200
|
+
.add_node(WorkflowNode::new("process", "process").with_input("review"));
|
|
201
|
+
|
|
202
|
+
runtime
|
|
203
|
+
.register_workflow(graph)
|
|
204
|
+
.expect("Failed to register workflow");
|
|
205
|
+
|
|
206
|
+
let instance_id = runtime
|
|
207
|
+
.create_instance(
|
|
208
|
+
workflow_ref.clone(),
|
|
209
|
+
"workflow-3",
|
|
210
|
+
vec![FlowRef::new("documents", "doc-1")],
|
|
211
|
+
)
|
|
212
|
+
.expect("Failed to create instance");
|
|
213
|
+
|
|
214
|
+
runtime
|
|
215
|
+
.start_instance(&instance_id)
|
|
216
|
+
.expect("Failed to start");
|
|
217
|
+
|
|
218
|
+
// Complete extract
|
|
219
|
+
runtime
|
|
220
|
+
.claim_step(&instance_id, "extract", "peer-a")
|
|
221
|
+
.expect("Failed to claim");
|
|
222
|
+
runtime
|
|
223
|
+
.step_completed(&instance_id, "extract", FlowRef::new("texts", "text-1"))
|
|
224
|
+
.expect("Failed to complete");
|
|
225
|
+
|
|
226
|
+
// Review should be ready
|
|
227
|
+
let ready = runtime.ready_steps(&instance_id);
|
|
228
|
+
assert!(ready.contains(&"review".to_string()));
|
|
229
|
+
|
|
230
|
+
// Claim review but immediately block it
|
|
231
|
+
runtime
|
|
232
|
+
.claim_step(&instance_id, "review", "peer-b")
|
|
233
|
+
.expect("Failed to claim");
|
|
234
|
+
runtime
|
|
235
|
+
.step_blocked(
|
|
236
|
+
&instance_id,
|
|
237
|
+
"review",
|
|
238
|
+
crate::BlockedReason::AwaitingApproval("Waiting for manager approval".to_string()),
|
|
239
|
+
)
|
|
240
|
+
.expect("Failed to block");
|
|
241
|
+
|
|
242
|
+
// Process should not be ready
|
|
243
|
+
let ready = runtime.ready_steps(&instance_id);
|
|
244
|
+
assert!(!ready.contains(&"process".to_string()));
|
|
245
|
+
|
|
246
|
+
// Unblock review
|
|
247
|
+
runtime
|
|
248
|
+
.unblock_step(&instance_id, "review")
|
|
249
|
+
.expect("Failed to unblock");
|
|
250
|
+
|
|
251
|
+
// Review should be ready again
|
|
252
|
+
let ready = runtime.ready_steps(&instance_id);
|
|
253
|
+
assert!(ready.contains(&"review".to_string()));
|
|
254
|
+
|
|
255
|
+
// Complete review
|
|
256
|
+
runtime
|
|
257
|
+
.step_completed(&instance_id, "review", FlowRef::new("reviews", "review-1"))
|
|
258
|
+
.expect("Failed to complete");
|
|
259
|
+
|
|
260
|
+
// Process should now be ready
|
|
261
|
+
let ready = runtime.ready_steps(&instance_id);
|
|
262
|
+
assert!(ready.contains(&"process".to_string()));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/// Test 4: Workflow continuation after peer failure
|
|
266
|
+
/// Demonstrates workflow mobility - workflow continues on different peer
|
|
267
|
+
#[test]
|
|
268
|
+
fn test_workflow_continues_on_peer_failure() {
|
|
269
|
+
let mut runtime = WorkflowRuntime::new();
|
|
270
|
+
|
|
271
|
+
let workflow_ref = WorkflowRef::new("workflow", "failover-test", 1);
|
|
272
|
+
let graph = WorkflowGraph::new(workflow_ref.clone())
|
|
273
|
+
.add_node(WorkflowNode::new("step1", "capability-a"))
|
|
274
|
+
.add_node(WorkflowNode::new("step2", "capability-b").with_input("step1"));
|
|
275
|
+
|
|
276
|
+
runtime
|
|
277
|
+
.register_workflow(graph)
|
|
278
|
+
.expect("Failed to register workflow");
|
|
279
|
+
|
|
280
|
+
let instance_id = runtime
|
|
281
|
+
.create_instance(workflow_ref.clone(), "workflow-4", Vec::new())
|
|
282
|
+
.expect("Failed to create instance");
|
|
283
|
+
|
|
284
|
+
runtime
|
|
285
|
+
.start_instance(&instance_id)
|
|
286
|
+
.expect("Failed to start");
|
|
287
|
+
|
|
288
|
+
// Step1 starts on peer-a
|
|
289
|
+
runtime
|
|
290
|
+
.claim_step(&instance_id, "step1", "peer-a")
|
|
291
|
+
.expect("Failed to claim");
|
|
292
|
+
runtime
|
|
293
|
+
.step_executing(&instance_id, "step1")
|
|
294
|
+
.expect("Failed to mark executing");
|
|
295
|
+
|
|
296
|
+
// Simulate peer-a failure by not completing
|
|
297
|
+
// The workflow is durable - the step state is preserved in the runtime
|
|
298
|
+
|
|
299
|
+
// Get the instance to verify state is persisted
|
|
300
|
+
let instance = runtime.get_instance(&instance_id).unwrap();
|
|
301
|
+
assert_eq!(
|
|
302
|
+
instance.get_step_state("step1"),
|
|
303
|
+
Some(crate::WorkflowStepState::Running)
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
// Another peer (peer-b) can read the workflow state and continue
|
|
307
|
+
// The step remains claimed but peer-b can check and proceed
|
|
308
|
+
// (In production, peer-b would acquire the workflow state from the fabric)
|
|
309
|
+
|
|
310
|
+
// For this test, we complete the step (simulating recovery and completion)
|
|
311
|
+
runtime
|
|
312
|
+
.step_completed(&instance_id, "step1", FlowRef::new("results", "result-1"))
|
|
313
|
+
.expect("Failed to complete");
|
|
314
|
+
|
|
315
|
+
// Step2 becomes ready and can be claimed by peer-c
|
|
316
|
+
let ready = runtime.ready_steps(&instance_id);
|
|
317
|
+
assert!(ready.contains(&"step2".to_string()));
|
|
318
|
+
|
|
319
|
+
runtime
|
|
320
|
+
.claim_step(&instance_id, "step2", "peer-c")
|
|
321
|
+
.expect("Failed to claim by peer-c");
|
|
322
|
+
runtime
|
|
323
|
+
.step_completed(&instance_id, "step2", FlowRef::new("results", "result-2"))
|
|
324
|
+
.expect("Failed to complete step2");
|
|
325
|
+
|
|
326
|
+
// Workflow completes
|
|
327
|
+
let instance = runtime.get_instance(&instance_id).unwrap();
|
|
328
|
+
assert_eq!(instance.state, crate::WorkflowState::Completed);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/// Test 5: Multiple concurrent workflows
|
|
332
|
+
/// Demonstrates independent workflow instances in the same runtime
|
|
333
|
+
#[test]
|
|
334
|
+
fn test_multiple_concurrent_workflows() {
|
|
335
|
+
let mut runtime = WorkflowRuntime::new();
|
|
336
|
+
|
|
337
|
+
// Define workflow
|
|
338
|
+
let workflow_ref = WorkflowRef::new("workflow", "multi-workflow", 1);
|
|
339
|
+
let graph = WorkflowGraph::new(workflow_ref.clone())
|
|
340
|
+
.add_node(WorkflowNode::new("step1", "capability-a"))
|
|
341
|
+
.add_node(WorkflowNode::new("step2", "capability-b").with_input("step1"))
|
|
342
|
+
.add_edge("step1", "step2");
|
|
343
|
+
|
|
344
|
+
runtime
|
|
345
|
+
.register_workflow(graph)
|
|
346
|
+
.expect("Failed to register workflow");
|
|
347
|
+
|
|
348
|
+
// Create multiple instances
|
|
349
|
+
let instance1 = runtime
|
|
350
|
+
.create_instance(workflow_ref.clone(), "wf-1", Vec::new())
|
|
351
|
+
.expect("Failed to create");
|
|
352
|
+
let instance2 = runtime
|
|
353
|
+
.create_instance(workflow_ref.clone(), "wf-2", Vec::new())
|
|
354
|
+
.expect("Failed to create");
|
|
355
|
+
let instance3 = runtime
|
|
356
|
+
.create_instance(workflow_ref.clone(), "wf-3", Vec::new())
|
|
357
|
+
.expect("Failed to create");
|
|
358
|
+
|
|
359
|
+
runtime.start_instance(&instance1).expect("Failed to start");
|
|
360
|
+
runtime.start_instance(&instance2).expect("Failed to start");
|
|
361
|
+
runtime.start_instance(&instance3).expect("Failed to start");
|
|
362
|
+
|
|
363
|
+
// All should have step1 ready
|
|
364
|
+
assert!(runtime
|
|
365
|
+
.ready_steps(&instance1)
|
|
366
|
+
.contains(&"step1".to_string()));
|
|
367
|
+
assert!(runtime
|
|
368
|
+
.ready_steps(&instance2)
|
|
369
|
+
.contains(&"step1".to_string()));
|
|
370
|
+
assert!(runtime
|
|
371
|
+
.ready_steps(&instance3)
|
|
372
|
+
.contains(&"step1".to_string()));
|
|
373
|
+
|
|
374
|
+
// Execute each workflow independently
|
|
375
|
+
for (instance_id, peer) in &[
|
|
376
|
+
(&instance1, "peer-a"),
|
|
377
|
+
(&instance2, "peer-b"),
|
|
378
|
+
(&instance3, "peer-c"),
|
|
379
|
+
] {
|
|
380
|
+
runtime
|
|
381
|
+
.claim_step(*instance_id, "step1", *peer)
|
|
382
|
+
.expect("Failed to claim");
|
|
383
|
+
runtime
|
|
384
|
+
.step_completed(
|
|
385
|
+
*instance_id,
|
|
386
|
+
"step1",
|
|
387
|
+
FlowRef::new("results", &format!("result-{}", peer)),
|
|
388
|
+
)
|
|
389
|
+
.expect("Failed to complete");
|
|
390
|
+
|
|
391
|
+
runtime
|
|
392
|
+
.claim_step(*instance_id, "step2", *peer)
|
|
393
|
+
.expect("Failed to claim");
|
|
394
|
+
runtime
|
|
395
|
+
.step_completed(
|
|
396
|
+
*instance_id,
|
|
397
|
+
"step2",
|
|
398
|
+
FlowRef::new("results", &format!("final-{}", peer)),
|
|
399
|
+
)
|
|
400
|
+
.expect("Failed to complete");
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// All workflows should be completed
|
|
404
|
+
assert_eq!(
|
|
405
|
+
runtime.get_instance(&instance1).unwrap().state,
|
|
406
|
+
crate::WorkflowState::Completed
|
|
407
|
+
);
|
|
408
|
+
assert_eq!(
|
|
409
|
+
runtime.get_instance(&instance2).unwrap().state,
|
|
410
|
+
crate::WorkflowState::Completed
|
|
411
|
+
);
|
|
412
|
+
assert_eq!(
|
|
413
|
+
runtime.get_instance(&instance3).unwrap().state,
|
|
414
|
+
crate::WorkflowState::Completed
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/// Test 6: Complex DAG with multiple dependencies
|
|
419
|
+
/// Tests the reactive advancement with more complex dependency patterns
|
|
420
|
+
#[test]
|
|
421
|
+
fn test_complex_dag_workflow() {
|
|
422
|
+
let mut runtime = WorkflowRuntime::new();
|
|
423
|
+
|
|
424
|
+
let workflow_ref = WorkflowRef::new("workflow", "complex-dag", 1);
|
|
425
|
+
let graph = WorkflowGraph::new(workflow_ref.clone())
|
|
426
|
+
.add_node(WorkflowNode::new("a", "cap-a"))
|
|
427
|
+
.add_node(WorkflowNode::new("b", "cap-b").with_input("a"))
|
|
428
|
+
.add_node(WorkflowNode::new("c", "cap-c").with_input("a"))
|
|
429
|
+
.add_node(
|
|
430
|
+
WorkflowNode::new("d", "cap-d")
|
|
431
|
+
.with_input("b")
|
|
432
|
+
.with_input("c"),
|
|
433
|
+
)
|
|
434
|
+
.add_node(WorkflowNode::new("e", "cap-e").with_input("d"))
|
|
435
|
+
.add_edge("a", "b")
|
|
436
|
+
.add_edge("a", "c")
|
|
437
|
+
.add_edge("b", "d")
|
|
438
|
+
.add_edge("c", "d")
|
|
439
|
+
.add_edge("d", "e");
|
|
440
|
+
|
|
441
|
+
runtime
|
|
442
|
+
.register_workflow(graph)
|
|
443
|
+
.expect("Failed to register workflow");
|
|
444
|
+
|
|
445
|
+
let instance_id = runtime
|
|
446
|
+
.create_instance(workflow_ref.clone(), "complex-1", Vec::new())
|
|
447
|
+
.expect("Failed to create");
|
|
448
|
+
|
|
449
|
+
runtime
|
|
450
|
+
.start_instance(&instance_id)
|
|
451
|
+
.expect("Failed to start");
|
|
452
|
+
|
|
453
|
+
// a should be ready
|
|
454
|
+
assert!(runtime.ready_steps(&instance_id).contains(&"a".to_string()));
|
|
455
|
+
|
|
456
|
+
// Complete a
|
|
457
|
+
runtime
|
|
458
|
+
.claim_step(&instance_id, "a", "peer-1")
|
|
459
|
+
.expect("Failed");
|
|
460
|
+
runtime
|
|
461
|
+
.step_completed(&instance_id, "a", FlowRef::new("res", "a-result"))
|
|
462
|
+
.expect("Failed");
|
|
463
|
+
|
|
464
|
+
// b and c should be ready
|
|
465
|
+
let ready = runtime.ready_steps(&instance_id);
|
|
466
|
+
assert!(ready.contains(&"b".to_string()));
|
|
467
|
+
assert!(ready.contains(&"c".to_string()));
|
|
468
|
+
|
|
469
|
+
// Complete b
|
|
470
|
+
runtime
|
|
471
|
+
.claim_step(&instance_id, "b", "peer-2")
|
|
472
|
+
.expect("Failed");
|
|
473
|
+
runtime
|
|
474
|
+
.step_completed(&instance_id, "b", FlowRef::new("res", "b-result"))
|
|
475
|
+
.expect("Failed");
|
|
476
|
+
|
|
477
|
+
// d should not be ready yet (c not done)
|
|
478
|
+
assert!(!runtime.ready_steps(&instance_id).contains(&"d".to_string()));
|
|
479
|
+
|
|
480
|
+
// Complete c
|
|
481
|
+
runtime
|
|
482
|
+
.claim_step(&instance_id, "c", "peer-3")
|
|
483
|
+
.expect("Failed");
|
|
484
|
+
runtime
|
|
485
|
+
.step_completed(&instance_id, "c", FlowRef::new("res", "c-result"))
|
|
486
|
+
.expect("Failed");
|
|
487
|
+
|
|
488
|
+
// Now d should be ready
|
|
489
|
+
assert!(runtime.ready_steps(&instance_id).contains(&"d".to_string()));
|
|
490
|
+
|
|
491
|
+
// Complete d and e
|
|
492
|
+
runtime
|
|
493
|
+
.claim_step(&instance_id, "d", "peer-4")
|
|
494
|
+
.expect("Failed");
|
|
495
|
+
runtime
|
|
496
|
+
.step_completed(&instance_id, "d", FlowRef::new("res", "d-result"))
|
|
497
|
+
.expect("Failed");
|
|
498
|
+
|
|
499
|
+
runtime
|
|
500
|
+
.claim_step(&instance_id, "e", "peer-5")
|
|
501
|
+
.expect("Failed");
|
|
502
|
+
runtime
|
|
503
|
+
.step_completed(&instance_id, "e", FlowRef::new("res", "e-result"))
|
|
504
|
+
.expect("Failed");
|
|
505
|
+
|
|
506
|
+
// Workflow should be completed
|
|
507
|
+
let instance = runtime.get_instance(&instance_id).unwrap();
|
|
508
|
+
assert_eq!(instance.state, crate::WorkflowState::Completed);
|
|
509
|
+
}
|
|
510
|
+
}
|