wfe-core 1.0.0

Core traits, models, builder, and executor for the WFE workflow engine
Documentation
use std::collections::HashMap;

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

use super::status::PointerStatus;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionPointer {
    pub id: String,
    pub step_id: usize,
    pub active: bool,
    pub status: PointerStatus,
    pub sleep_until: Option<DateTime<Utc>>,
    pub persistence_data: Option<serde_json::Value>,
    pub start_time: Option<DateTime<Utc>>,
    pub end_time: Option<DateTime<Utc>>,
    pub event_name: Option<String>,
    pub event_key: Option<String>,
    pub event_published: bool,
    pub event_data: Option<serde_json::Value>,
    pub step_name: Option<String>,
    pub retry_count: u32,
    pub children: Vec<String>,
    pub context_item: Option<serde_json::Value>,
    pub predecessor_id: Option<String>,
    pub outcome: Option<serde_json::Value>,
    pub scope: Vec<String>,
    pub extension_attributes: HashMap<String, serde_json::Value>,
}

impl ExecutionPointer {
    pub fn new(step_id: usize) -> Self {
        Self {
            id: uuid::Uuid::new_v4().to_string(),
            step_id,
            active: true,
            status: PointerStatus::Pending,
            sleep_until: None,
            persistence_data: None,
            start_time: None,
            end_time: None,
            event_name: None,
            event_key: None,
            event_published: false,
            event_data: None,
            step_name: None,
            retry_count: 0,
            children: Vec::new(),
            context_item: None,
            predecessor_id: None,
            outcome: None,
            scope: Vec::new(),
            extension_attributes: HashMap::new(),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn new_pointer_has_correct_defaults() {
        let pointer = ExecutionPointer::new(0);
        assert_eq!(pointer.step_id, 0);
        assert!(pointer.active);
        assert_eq!(pointer.status, PointerStatus::Pending);
        assert_eq!(pointer.retry_count, 0);
        assert!(pointer.children.is_empty());
        assert!(pointer.scope.is_empty());
        assert!(!pointer.event_published);
    }

    #[test]
    fn new_pointer_generates_unique_ids() {
        let p1 = ExecutionPointer::new(0);
        let p2 = ExecutionPointer::new(0);
        assert_ne!(p1.id, p2.id);
    }

    #[test]
    fn serde_round_trip() {
        let mut pointer = ExecutionPointer::new(3);
        pointer.status = PointerStatus::Running;
        pointer.retry_count = 2;
        pointer.persistence_data = Some(serde_json::json!({"step_state": true}));
        pointer.children = vec!["child-1".into(), "child-2".into()];

        let json = serde_json::to_string(&pointer).unwrap();
        let deserialized: ExecutionPointer = serde_json::from_str(&json).unwrap();

        assert_eq!(pointer.id, deserialized.id);
        assert_eq!(pointer.step_id, deserialized.step_id);
        assert_eq!(pointer.status, deserialized.status);
        assert_eq!(pointer.retry_count, deserialized.retry_count);
        assert_eq!(pointer.persistence_data, deserialized.persistence_data);
        assert_eq!(pointer.children, deserialized.children);
    }
}