#![no_main] use libfuzzer_sys::fuzz_target; use dagx::{task, DagRunner}; use std::sync::Arc; fuzz_target!(|data: &[u8]| { if data.is_empty() || data.len() > 50 { return; } let rt = tokio::runtime::Runtime::new().unwrap(); // Test concurrent task execution struct SlowTask { val: i32, delay_ms: u64 } #[task] impl SlowTask { async fn run(&self) -> i32 { tokio::time::sleep(tokio::time::Duration::from_millis(self.delay_ms)).await; self.val } } struct FastTask { val: i32 } #[task] impl FastTask { async fn run(&self) -> i32 { self.val } } // Test concurrent independent tasks { let dag = DagRunner::new(); // Create multiple independent tasks let num_tasks = (data[0] % 5 + 1) as usize; let mut tasks = Vec::new(); for i in 0..num_tasks { let val = data.get(i).copied().unwrap_or(0) as i32; let delay = (val.abs() as u64 % 10) + 1; let task = dag.add_task(SlowTask { val, delay_ms: delay }); tasks.push((task, val)); } if rt.block_on(async { dag.run(|fut| { tokio::spawn(fut); }).await }).is_ok() { // Verify all tasks completed with correct values for (handle, expected) in tasks { if let Ok(result) = dag.get(handle) { assert_eq!(result, expected); } } } } // Test concurrent dependent tasks { let dag = DagRunner::new(); let source = dag.add_task(FastTask { val: data[0] as i32 }); // Create multiple tasks that depend on source struct AddOne; #[task] impl AddOne { async fn run(input: &i32) -> i32 { input.wrapping_add(1) } } struct AddTwo; #[task] impl AddTwo { async fn run(input: &i32) -> i32 { input.wrapping_add(2) } } struct AddThree; #[task] impl AddThree { async fn run(input: &i32) -> i32 { input.wrapping_add(3) } } let t1 = dag.add_task(AddOne).depends_on(&source); let t2 = dag.add_task(AddTwo).depends_on(&source); let t3 = dag.add_task(AddThree).depends_on(&source); if rt.block_on(async { dag.run(|fut| { tokio::spawn(fut); }).await }).is_ok() { let base = data[0] as i32; if let Ok(r1) = dag.get(t1) { assert_eq!(r1, base.wrapping_add(1)); } if let Ok(r2) = dag.get(t2) { assert_eq!(r2, base.wrapping_add(2)); } if let Ok(r3) = dag.get(t3) { assert_eq!(r3, base.wrapping_add(3)); } } } // Test Arc sharing across concurrent tasks { let dag = Arc::new(DagRunner::new()); struct SharedTask { val: i32 } #[task] impl SharedTask { async fn run(&self) -> i32 { self.val } } let task = dag.add_task(SharedTask { val: data[0] as i32 }); let task_copy = task; let dag1 = Arc::clone(&dag); let dag2 = Arc::clone(&dag); if rt.block_on(async { dag.run(|fut| { tokio::spawn(fut); }).await }).is_ok() { // Multiple threads can access result if let Ok(r1) = dag1.get(task_copy) { if let Ok(r2) = dag2.get(task_copy) { assert_eq!(r1, r2); assert_eq!(r1, data[0] as i32); } } } } });