use cloacina::{task, Context, Task, TaskError, TaskNamespace, TaskRegistry};
use serde_json::Value;
#[task(id = "macro-test-simple-task", dependencies = [])]
async fn simple_task(context: &mut Context<Value>) -> Result<(), TaskError> {
context
.insert("processed", Value::Bool(true))
.map_err(|e| TaskError::ExecutionFailed {
message: format!("Context error: {:?}", e),
task_id: "macro-test-simple-task".to_string(),
timestamp: chrono::Utc::now(),
})?;
Ok(())
}
#[task(id = "macro-test-dependent-task", dependencies = ["macro-test-simple-task"])]
async fn dependent_task(context: &mut Context<Value>) -> Result<(), TaskError> {
let _processed = context
.get("processed")
.ok_or_else(|| TaskError::ExecutionFailed {
message: "Missing 'processed' key".to_string(),
task_id: "macro-test-dependent-task".to_string(),
timestamp: chrono::Utc::now(),
})?;
context
.insert("dependent_processed", Value::Bool(true))
.map_err(|e| TaskError::ExecutionFailed {
message: format!("Context error: {:?}", e),
task_id: "macro-test-dependent-task".to_string(),
timestamp: chrono::Utc::now(),
})?;
Ok(())
}
#[tokio::test]
async fn test_macro_generated_task() {
let task = simple_task_task();
assert_eq!(task.id(), "macro-test-simple-task");
assert_eq!(task.dependencies(), &[] as &[TaskNamespace]);
let context = Context::new();
let result = task.execute(context).await;
assert!(result.is_ok());
let context = result.unwrap();
assert_eq!(context.get("processed"), Some(&Value::Bool(true)));
}
#[tokio::test]
async fn test_macro_with_dependencies() {
let task = dependent_task_task();
assert_eq!(task.id(), "macro-test-dependent-task");
assert_eq!(
DependentTaskTask::dependency_task_ids(),
&["macro-test-simple-task"]
);
assert_eq!(task.dependencies(), &[] as &[TaskNamespace]);
}
#[tokio::test]
async fn test_task_registry_with_macro_tasks() {
let mut registry = TaskRegistry::new();
let ns1 = TaskNamespace::new(
"public",
"embedded",
"test_workflow",
"macro-test-simple-task",
);
let ns2 = TaskNamespace::new(
"public",
"embedded",
"test_workflow",
"macro-test-dependent-task",
);
let simple_task = simple_task_task();
let dependent_task = dependent_task_task().with_dependencies(vec![ns1.clone()]);
registry.register(ns1.clone(), simple_task).unwrap();
registry.register(ns2.clone(), dependent_task).unwrap();
assert!(registry.validate_dependencies().is_ok());
let sorted = registry.topological_sort().unwrap();
let simple_pos = sorted
.iter()
.position(|x| x.task_id == "macro-test-simple-task")
.unwrap();
let dependent_pos = sorted
.iter()
.position(|x| x.task_id == "macro-test-dependent-task")
.unwrap();
assert!(simple_pos < dependent_pos);
}
#[tokio::test]
async fn test_task_execution_flow() {
let mut registry = TaskRegistry::new();
let ns1 = TaskNamespace::new(
"public",
"embedded",
"test_workflow",
"macro-test-simple-task",
);
let ns2 = TaskNamespace::new(
"public",
"embedded",
"test_workflow",
"macro-test-dependent-task",
);
let simple_task = simple_task_task();
let dependent_task = dependent_task_task().with_dependencies(vec![ns1.clone()]);
registry.register(ns1.clone(), simple_task).unwrap();
registry.register(ns2.clone(), dependent_task).unwrap();
let sorted = registry.topological_sort().unwrap();
let mut context = Context::new();
for task_ns in sorted {
let task = registry.get_task(&task_ns).unwrap();
context = task.execute(context).await.unwrap();
}
assert_eq!(context.get("processed"), Some(&Value::Bool(true)));
assert_eq!(context.get("dependent_processed"), Some(&Value::Bool(true)));
}
#[tokio::test]
async fn test_original_function_available() {
let mut context = Context::new();
let result = simple_task(&mut context).await;
assert!(result.is_ok());
assert_eq!(context.get("processed"), Some(&Value::Bool(true)));
}