dag-executor 0.1.0

A production-ready DAG executor with state management and advanced patterns
Documentation
//! Unit tests for the dependency graph.

use crate::fixtures::ok_task;
use dag_executor::prelude::*;

#[test]
fn validates_a_well_formed_dag() {
    let mut dag = Dag::new();
    dag.add_task(ok_task("a", &[])).unwrap();
    dag.add_task(ok_task("b", &["a"])).unwrap();
    dag.add_task(ok_task("c", &["a", "b"])).unwrap();
    assert!(dag.validate().is_ok());
    assert_eq!(dag.len(), 3);
}

#[test]
fn rejects_duplicate_task_ids() {
    let mut dag = Dag::new();
    dag.add_task(ok_task("a", &[])).unwrap();
    let err = dag.add_task(ok_task("a", &[])).unwrap_err();
    assert!(matches!(
        err,
        DagExecutorError::Validation(ValidationError::DuplicateTask(_))
    ));
}

#[test]
fn rejects_self_dependency() {
    let mut dag = Dag::new();
    let err = dag.add_task(ok_task("a", &["a"])).unwrap_err();
    assert!(matches!(
        err,
        DagExecutorError::Validation(ValidationError::SelfDependency(_))
    ));
}

#[test]
fn detects_missing_dependency() {
    let mut dag = Dag::new();
    dag.add_task(ok_task("a", &["ghost"])).unwrap();
    let err = dag.validate().unwrap_err();
    assert!(matches!(
        err,
        DagExecutorError::Validation(ValidationError::MissingDependency { .. })
    ));
}

#[test]
fn detects_cycles() {
    let mut dag = Dag::new();
    dag.add_task(ok_task("a", &["b"])).unwrap();
    dag.add_task(ok_task("b", &["a"])).unwrap();
    let err = dag.validate().unwrap_err();
    assert!(matches!(
        err,
        DagExecutorError::Validation(ValidationError::Cycle(_))
    ));
}

#[test]
fn topological_order_respects_dependencies() {
    let mut dag = Dag::new();
    dag.add_task(ok_task("a", &[])).unwrap();
    dag.add_task(ok_task("b", &["a"])).unwrap();
    dag.add_task(ok_task("c", &["b"])).unwrap();
    let order = dag.topological_order().unwrap();
    let pos = |id: &str| order.iter().position(|x| x == id).unwrap();
    assert!(pos("a") < pos("b"));
    assert!(pos("b") < pos("c"));
}

#[test]
fn tracks_dependents_and_dependencies() {
    let mut dag = Dag::new();
    dag.add_task(ok_task("a", &[])).unwrap();
    dag.add_task(ok_task("b", &["a"])).unwrap();
    dag.add_task(ok_task("c", &["a"])).unwrap();

    let mut deps = dag.dependencies_of("b");
    deps.sort();
    assert_eq!(deps, vec!["a".to_string()]);

    let mut dependents = dag.dependents_of("a");
    dependents.sort();
    assert_eq!(dependents, vec!["b".to_string(), "c".to_string()]);
}