Files
wfe/wfe-yaml/tests/compiler.rs

226 lines
5.2 KiB
Rust
Raw Normal View History

use std::collections::HashMap;
use std::time::Duration;
use wfe_core::models::error_behavior::ErrorBehavior;
use wfe_yaml::load_workflow_from_str;
#[test]
fn single_step_produces_one_workflow_step() {
let yaml = r#"
workflow:
id: single
version: 1
steps:
- name: hello
type: shell
config:
run: echo hello
"#;
let compiled = load_workflow_from_str(yaml, &HashMap::new()).unwrap();
// The definition should have exactly 1 main step.
let main_steps: Vec<_> = compiled
.definition
.steps
.iter()
.filter(|s| s.name.as_deref() == Some("hello"))
.collect();
assert_eq!(main_steps.len(), 1);
assert_eq!(main_steps[0].id, 0);
}
#[test]
fn two_sequential_steps_wired_correctly() {
let yaml = r#"
workflow:
id: sequential
version: 1
steps:
- name: step-a
type: shell
config:
run: echo a
- name: step-b
type: shell
config:
run: echo b
"#;
let compiled = load_workflow_from_str(yaml, &HashMap::new()).unwrap();
let step_a = compiled
.definition
.steps
.iter()
.find(|s| s.name.as_deref() == Some("step-a"))
.unwrap();
let step_b = compiled
.definition
.steps
.iter()
.find(|s| s.name.as_deref() == Some("step-b"))
.unwrap();
// step-a should have an outcome pointing to step-b.
assert_eq!(step_a.outcomes.len(), 1);
assert_eq!(step_a.outcomes[0].next_step, step_b.id);
}
#[test]
fn parallel_block_produces_container_with_children() {
let yaml = r#"
workflow:
id: parallel-wf
version: 1
steps:
- name: parallel-group
parallel:
- name: task-a
type: shell
config:
run: echo a
- name: task-b
type: shell
config:
run: echo b
"#;
let compiled = load_workflow_from_str(yaml, &HashMap::new()).unwrap();
let container = compiled
.definition
.steps
.iter()
.find(|s| s.name.as_deref() == Some("parallel-group"))
.unwrap();
assert!(
container.step_type.contains("SequenceStep"),
"Container should be a SequenceStep, got: {}",
container.step_type
);
assert_eq!(container.children.len(), 2);
}
#[test]
fn on_failure_creates_compensation_step() {
let yaml = r#"
workflow:
id: compensation-wf
version: 1
steps:
- name: deploy
type: shell
config:
run: deploy.sh
on_failure:
name: rollback
type: shell
config:
run: rollback.sh
"#;
let compiled = load_workflow_from_str(yaml, &HashMap::new()).unwrap();
let deploy = compiled
.definition
.steps
.iter()
.find(|s| s.name.as_deref() == Some("deploy"))
.unwrap();
assert!(deploy.compensation_step_id.is_some());
assert_eq!(deploy.error_behavior, Some(ErrorBehavior::Compensate));
let rollback = compiled
.definition
.steps
.iter()
.find(|s| s.name.as_deref() == Some("rollback"))
.unwrap();
assert_eq!(deploy.compensation_step_id, Some(rollback.id));
}
#[test]
fn error_behavior_maps_correctly() {
let yaml = r#"
workflow:
id: retry-wf
version: 1
error_behavior:
type: retry
interval: 5s
max_retries: 10
steps:
- name: step1
type: shell
config:
run: echo hi
error_behavior:
type: suspend
"#;
let compiled = load_workflow_from_str(yaml, &HashMap::new()).unwrap();
assert_eq!(
compiled.definition.default_error_behavior,
ErrorBehavior::Retry {
interval: Duration::from_secs(5),
max_retries: 10,
}
);
let step = compiled
.definition
.steps
.iter()
.find(|s| s.name.as_deref() == Some("step1"))
.unwrap();
assert_eq!(step.error_behavior, Some(ErrorBehavior::Suspend));
}
#[test]
fn anchors_compile_correctly() {
let yaml = r#"
workflow:
id: anchor-wf
version: 1
steps:
- name: build
type: shell
config: &default_config
shell: bash
timeout: 5m
run: cargo build
- name: test
type: shell
config: *default_config
"#;
let compiled = load_workflow_from_str(yaml, &HashMap::new()).unwrap();
// Should have 2 main steps + factories.
let build_step = compiled
.definition
.steps
.iter()
.find(|s| s.name.as_deref() == Some("build"))
.unwrap();
let test_step = compiled
.definition
.steps
.iter()
.find(|s| s.name.as_deref() == Some("test"))
.unwrap();
// Both should have step_config.
assert!(build_step.step_config.is_some());
assert!(test_step.step_config.is_some());
// Build should wire to test.
assert_eq!(build_step.outcomes.len(), 1);
assert_eq!(build_step.outcomes[0].next_step, test_step.id);
// Test uses the same config via alias - shell should be bash.
let test_config: wfe_yaml::executors::shell::ShellConfig =
serde_json::from_value(test_step.step_config.clone().unwrap()).unwrap();
assert_eq!(test_config.run, "cargo build");
assert_eq!(test_config.shell, "bash", "shell should be inherited from YAML anchor alias");
}