Skip to content

Commit 5b4bf04

Browse files
Merge pull request #203 from code0-tech/#185-handle-test-exec
handle test execution
2 parents 39f87ac + 99c3af9 commit 5b4bf04

23 files changed

Lines changed: 779 additions & 157 deletions

File tree

.github/workflows/build-and-test.yml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ on:
66
jobs:
77
taurus:
88
runs-on: ubuntu-latest
9+
services:
10+
nats:
11+
image: nats:2
12+
ports:
13+
- 4222:4222
914

1015
steps:
1116
- uses: actions/checkout@v6
@@ -15,8 +20,11 @@ jobs:
1520
run: PATH=${{ runner.temp }}/proto/bin:$PATH cargo build
1621
env:
1722
RUST_BACKTRACE: 'full'
18-
- name: Run Tests
19-
run: cargo test
20-
- name: Run Test Suite
23+
- name: Run workspace tests
24+
run: cargo test --workspace --all-targets
25+
- name: Run NATS test execution request tests
26+
run: cargo test -p taurus test_execution_request -- --ignored --nocapture
27+
env:
28+
NATS_URL: nats://127.0.0.1:4222
29+
- name: Run tests package flow suite
2130
run: cargo run --package tests
22-

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/taurus-core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
66
mod handler;
77
pub mod runtime;
8+
pub mod time;
89
pub mod types;
910
pub mod value;

crates/taurus-core/src/runtime/engine.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,8 @@ mod tests {
170170
use crate::types::exit_reason::ExitReason;
171171
use std::cell::RefCell;
172172
use tucana::shared::{
173-
InputType, ListValue, NodeParameter, NodeValue, ReferenceValue, Struct, Value, node_value,
174-
reference_value, value::Kind,
173+
InputType, ListValue, NodeParameter, NodeValue, ReferenceValue, Struct, SubFlow, Value,
174+
node_value, reference_value, sub_flow::ExecutionReference, value::Kind,
175175
};
176176

177177
fn literal_param(database_id: i64, runtime_parameter_id: &str, value: Value) -> NodeParameter {
@@ -190,9 +190,11 @@ mod tests {
190190
database_id,
191191
runtime_parameter_id: runtime_parameter_id.to_string(),
192192
value: Some(NodeValue {
193-
value: Some(node_value::Value::SubFlow(unimplemented!(
194-
"Taurus needs to handle SubFlows (issue nr #184)"
195-
))),
193+
value: Some(node_value::Value::SubFlow(SubFlow {
194+
signature: String::new(),
195+
settings: Vec::new(),
196+
execution_reference: Some(ExecutionReference::StartingNodeId(node_id)),
197+
})),
196198
}),
197199
cast: None,
198200
}

crates/taurus-core/src/runtime/engine/compiler.rs

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::collections::HashMap;
44

5-
use tucana::shared::{NodeFunction, node_value};
5+
use tucana::shared::{NodeFunction, node_value, sub_flow};
66

77
use crate::{
88
runtime::engine::model::{
@@ -27,6 +27,15 @@ pub enum CompileError {
2727
node_id: i64,
2828
parameter_index: usize,
2929
},
30+
SubFlowExecutionReferenceMissing {
31+
node_id: i64,
32+
parameter_index: usize,
33+
},
34+
SubFlowFunctionIdentifierUnsupported {
35+
node_id: i64,
36+
parameter_index: usize,
37+
function_identifier: String,
38+
},
3039
}
3140

3241
impl CompileError {
@@ -64,6 +73,29 @@ impl CompileError {
6473
node_id, parameter_index
6574
),
6675
),
76+
CompileError::SubFlowExecutionReferenceMissing {
77+
node_id,
78+
parameter_index,
79+
} => RuntimeError::new(
80+
"T-CORE-000105",
81+
"FlowCompileError",
82+
format!(
83+
"Node {} parameter {} sub_flow is missing execution reference",
84+
node_id, parameter_index
85+
),
86+
),
87+
CompileError::SubFlowFunctionIdentifierUnsupported {
88+
node_id,
89+
parameter_index,
90+
function_identifier,
91+
} => RuntimeError::new(
92+
"T-CORE-000106",
93+
"FlowCompileError",
94+
format!(
95+
"Node {} parameter {} uses unsupported sub_flow function identifier {}",
96+
node_id, parameter_index, function_identifier
97+
),
98+
),
6799
}
68100
}
69101
}
@@ -125,7 +157,26 @@ pub fn compile_flow(
125157
let arg = match value {
126158
node_value::Value::LiteralValue(v) => CompiledArg::Literal(v.clone()),
127159
node_value::Value::ReferenceValue(r) => CompiledArg::Reference(r.clone()),
128-
node_value::Value::SubFlow(_sub_flow) => unimplemented!("Taurus needs to handle SubFlows (issue nr #184)"),
160+
node_value::Value::SubFlow(sub_flow) => {
161+
match sub_flow.execution_reference.as_ref() {
162+
Some(sub_flow::ExecutionReference::StartingNodeId(node_id)) => {
163+
CompiledArg::DeferredNode(*node_id)
164+
}
165+
Some(sub_flow::ExecutionReference::FunctionIdentifier(identifier)) => {
166+
return Err(CompileError::SubFlowFunctionIdentifierUnsupported {
167+
node_id: node.database_id,
168+
parameter_index,
169+
function_identifier: identifier.clone(),
170+
});
171+
}
172+
None => {
173+
return Err(CompileError::SubFlowExecutionReferenceMissing {
174+
node_id: node.database_id,
175+
parameter_index,
176+
});
177+
}
178+
}
179+
}
129180
};
130181

131182
parameters.push(CompiledParameter {

crates/taurus-core/src/runtime/engine/executor.rs

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ use std::collections::HashMap;
55

66
use futures_lite::future::block_on;
77
use tucana::aquila::ActionExecutionRequest;
8+
use tucana::shared::node_execution_result::Result as TucanaNodeResult;
89
use tucana::shared::reference_value::Target;
910
use tucana::shared::value::Kind;
10-
use tucana::shared::{Struct, Value};
11+
use tucana::shared::{NodeExecutionResult as TucanaNodeExecutionResult, Struct, Value};
1112
use uuid::Uuid;
1213

1314
use crate::handler::argument::{Argument, ParameterNode};
@@ -56,7 +57,7 @@ struct ExecutionResult {
5657
}
5758

5859
/// Result of executing exactly one compiled node.
59-
struct NodeExecutionResult {
60+
struct NodeResult {
6061
signal: Signal,
6162
frame_id: Option<u64>,
6263
}
@@ -150,25 +151,24 @@ impl<'a> EngineExecutor<'a> {
150151
}
151152
}
152153

153-
fn execute_single_node(
154-
&self,
155-
node_idx: usize,
156-
value_store: &mut ValueStore,
157-
) -> NodeExecutionResult {
154+
fn execute_single_node(&self, node_idx: usize, value_store: &mut ValueStore) -> NodeResult {
158155
let node = &self.flow.nodes[node_idx];
159156
// InputType references resolve against the currently running node.
160157
value_store.set_current_node_id(node.id);
161158

162159
let frame_id = self.trace_enter(node, value_store);
163160
let signal = match &node.execution_target {
164-
NodeExecutionTarget::Local => self.execute_local_node(node, value_store, frame_id),
161+
NodeExecutionTarget::Local => {
162+
let signal = self.execute_local_node(node, value_store, frame_id);
163+
self.commit_result(node.id, signal, value_store)
164+
}
165165
NodeExecutionTarget::Remote { service } => {
166166
self.execute_remote_node(node, service, value_store, frame_id)
167167
}
168168
};
169169
self.trace_exit(frame_id, &signal, value_store);
170170

171-
NodeExecutionResult { signal, frame_id }
171+
NodeResult { signal, frame_id }
172172
}
173173

174174
fn execute_local_node(
@@ -190,14 +190,11 @@ impl<'a> EngineExecutor<'a> {
190190

191191
let mut args = match self.build_args(node, value_store, frame_id) {
192192
Ok(args) => args,
193-
Err(err) => {
194-
value_store.insert_error(node.id, err.clone());
195-
return Signal::Failure(err);
196-
}
193+
Err(err) => return Signal::Failure(err),
197194
};
198195

199196
if let Some(signal) = self.force_eager_args(entry, &mut args, value_store, frame_id) {
200-
return self.commit_result(node.id, signal, value_store);
197+
return signal;
201198
}
202199

203200
// Handler-owned runtime calls (for lazy args / callbacks) re-enter the same executor.
@@ -211,8 +208,7 @@ impl<'a> EngineExecutor<'a> {
211208
child_result.signal
212209
};
213210

214-
let signal = (entry.handler)(&args, value_store, &mut run);
215-
self.commit_result(node.id, signal, value_store)
211+
(entry.handler)(&args, value_store, &mut run)
216212
}
217213

218214
fn execute_remote_node(
@@ -225,20 +221,21 @@ impl<'a> EngineExecutor<'a> {
225221
let remote_runtime = match self.remote {
226222
Some(remote) => remote,
227223
None => {
228-
return Signal::Failure(RuntimeError::new(
229-
"T-CORE-000003",
230-
"RemoteRuntimeNotConfigured",
231-
"Remote runtime not configured",
232-
));
224+
return self.commit_result(
225+
node.id,
226+
Signal::Failure(RuntimeError::new(
227+
"T-CORE-000003",
228+
"RemoteRuntimeNotConfigured",
229+
"Remote runtime not configured",
230+
)),
231+
value_store,
232+
);
233233
}
234234
};
235235

236236
let mut args = match self.build_args(node, value_store, frame_id) {
237237
Ok(args) => args,
238-
Err(err) => {
239-
value_store.insert_error(node.id, err.clone());
240-
return Signal::Failure(err);
241-
}
238+
Err(err) => return self.commit_result(node.id, Signal::Failure(err), value_store),
242239
};
243240

244241
let values = match self.resolve_remote_args(&mut args, value_store, frame_id) {
@@ -248,21 +245,16 @@ impl<'a> EngineExecutor<'a> {
248245

249246
let request = match self.build_remote_request(node, values) {
250247
Ok(request) => request,
251-
Err(err) => {
252-
value_store.insert_error(node.id, err.clone());
253-
return Signal::Failure(err);
254-
}
248+
Err(err) => return self.commit_result(node.id, Signal::Failure(err), value_store),
255249
};
256250

257-
let signal = match block_on(remote_runtime.execute_remote(RemoteExecution {
251+
match block_on(remote_runtime.execute_remote(RemoteExecution {
258252
target_service: service.to_string(),
259253
request,
260254
})) {
261-
Ok(value) => Signal::Success(value),
262-
Err(err) => Signal::Failure(err),
263-
};
264-
265-
self.commit_result(node.id, signal, value_store)
255+
Ok(result) => self.commit_remote_result(node.id, result, value_store),
256+
Err(err) => self.commit_result(node.id, Signal::Failure(err), value_store),
257+
}
266258
}
267259

268260
fn build_args(
@@ -522,6 +514,26 @@ impl<'a> EngineExecutor<'a> {
522514
}
523515
}
524516

517+
fn commit_remote_result(
518+
&self,
519+
node_id: i64,
520+
result: TucanaNodeExecutionResult,
521+
value_store: &mut ValueStore,
522+
) -> Signal {
523+
value_store.insert_node_result(node_id, result.clone());
524+
match result.result {
525+
Some(TucanaNodeResult::Success(value)) => Signal::Success(value),
526+
Some(TucanaNodeResult::Error(error)) => {
527+
Signal::Failure(RuntimeError::from_tucana_error(&error))
528+
}
529+
None => Signal::Failure(RuntimeError::new(
530+
"T-CORE-000006",
531+
"NodeExecutionResultMissingOutcome",
532+
"Remote node execution result is missing success/error outcome",
533+
)),
534+
}
535+
}
536+
525537
fn trace_enter(&self, node: &CompiledNode, value_store: &ValueStore) -> Option<u64> {
526538
self.tracer.map(|tracer| {
527539
tracer.borrow_mut().enter_node(

crates/taurus-core/src/runtime/execution/render.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22
33
use std::collections::HashMap;
44

5+
use tucana::shared::node_execution_result::Result as TucanaNodeResult;
6+
57
use crate::runtime::execution::trace::{
6-
ArgKind, EdgeKind, Outcome, StoreDiff, StoreResultStatus, TraceFrame, TraceRun,
8+
ArgKind, EdgeKind, Outcome, StoreDiff, TraceFrame, TraceRun,
79
};
810

911
struct TraceTheme;
@@ -266,14 +268,17 @@ fn render_store_diff(
266268
}
267269

268270
for set in &diff.result_sets {
269-
let status = match set.status {
270-
StoreResultStatus::Success => "success",
271-
StoreResultStatus::Error => "error",
271+
let status = match &set.result.result {
272+
Some(TucanaNodeResult::Success(_)) => "success",
273+
Some(TucanaNodeResult::Error(_)) => "error",
274+
None => "empty",
272275
};
273276
out.push_str(&format!(
274-
"{step:04} {prefix}{continuation}{store:<5} result.set node={} [{}] {}\n",
277+
"{step:04} {prefix}{continuation}{store:<5} result.set node={} [{}] started_at={} finished_at={} {}\n",
275278
set.node_id,
276279
status,
280+
set.result.started_at,
281+
set.result.finished_at,
277282
set.preview,
278283
step = *step,
279284
prefix = prefix,

crates/taurus-core/src/runtime/execution/store.rs

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,10 @@
22
33
use std::collections::HashMap;
44

5-
use tucana::shared::Value;
5+
use tucana::shared::{NodeExecutionResult, Value};
66

7-
use crate::types::errors::runtime_error::RuntimeError;
87
use crate::types::execution::ids::{FrameId, NodeId};
98

10-
/// Runtime outcome persisted per node.
11-
#[derive(Debug, Clone)]
12-
pub enum NodeOutcome {
13-
Success(Value),
14-
Failure(RuntimeError),
15-
}
16-
179
/// Input slot key for runtime-provided temporary inputs (for iterators/predicates).
1810
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1911
pub struct InputSlotKey {
@@ -25,7 +17,7 @@ pub struct InputSlotKey {
2517
/// Store that captures mutable runtime execution state.
2618
#[derive(Debug, Clone, Default)]
2719
pub struct ExecutionStore {
28-
pub node_outcomes: HashMap<NodeId, NodeOutcome>,
20+
pub node_results: HashMap<NodeId, NodeExecutionResult>,
2921
pub input_slots: HashMap<InputSlotKey, Value>,
3022
pub flow_input: Option<Value>,
3123
pub current_node: Option<NodeId>,

0 commit comments

Comments
 (0)