use std::time; use context_async::{Context, Error, TimeChecker, Timer}; #[tokio::test] async fn test_timer_deadline() { let timer = Timer::background(); assert!(timer.deadline().await.is_none()); let timer = Timer::todo(); assert!(timer.deadline().await.is_none()); let now = time::Instant::now(); let timer = Timer::with_timeout(time::Duration::from_secs(10)); let deadline = timer.deadline().await; assert!(deadline.is_some()); let deadline = deadline.unwrap(); let diff = deadline - (now + time::Duration::from_secs(10)); assert!(diff < time::Duration::from_millis(100)); } #[tokio::test] async fn test_timer_cancel() { let timer = Timer::background(); let timer_1 = timer.clone(); let child_1 = timer.spawn().await; let child_1_clone = child_1.clone(); let child_2 = timer_1.spawn().await; let child_1_1 = child_1.spawn().await; let child_1_2 = child_1_clone.spawn().await; let child_1_1_1 = child_1_1.spawn().await; let child_2_1_1 = child_2.spawn().await.spawn().await; assert!(!timer.is_cancelled().await); assert!(!child_2_1_1.is_cancelled().await); child_1.cancel().await; assert!(!timer.is_cancelled().await); assert!(!timer_1.is_cancelled().await); assert!(child_1.is_cancelled().await); assert!(child_1_clone.is_cancelled().await); assert!(child_1_1.is_cancelled().await); assert!(child_1_2.is_cancelled().await); assert!(child_1_1_1.is_cancelled().await); assert!(!child_2.is_cancelled().await); assert!(!child_2_1_1.is_cancelled().await); child_2_1_1.cancel().await; assert!(!timer.is_cancelled().await); assert!(!timer_1.is_cancelled().await); assert!(child_1.is_cancelled().await); assert!(child_1_clone.is_cancelled().await); assert!(child_1_1.is_cancelled().await); assert!(child_1_2.is_cancelled().await); assert!(child_1_1_1.is_cancelled().await); assert!(!child_2.is_cancelled().await); assert!(child_2_1_1.is_cancelled().await); timer_1.cancel().await; assert!(timer.is_cancelled().await); assert!(timer_1.is_cancelled().await); assert!(child_1.is_cancelled().await); assert!(child_1_clone.is_cancelled().await); assert!(child_1_1.is_cancelled().await); assert!(child_1_2.is_cancelled().await); assert!(child_1_1_1.is_cancelled().await); assert!(child_2.is_cancelled().await); assert!(child_2_1_1.is_cancelled().await); assert!(child_2_1_1.is_cancelled().await); assert_eq!(child_2_1_1.error().await, Some(Error::ContextCancelled)); } #[tokio::test] async fn test_timer_timeout() { let timer = Timer::with_timeout(time::Duration::from_secs(1)); assert!(!timer.is_timeout().await); tokio::time::sleep(time::Duration::from_secs(2)).await; assert!(timer.is_timeout().await); // check child timeout... let timer = Timer::with_timeout(time::Duration::from_secs(10)); let child = timer.spawn_with_timeout(time::Duration::from_secs(1)).await; tokio::time::sleep(time::Duration::from_secs(2)).await; assert!(!timer.is_timeout().await); assert!(child.is_timeout().await); let timer = Timer::with_timeout(time::Duration::from_secs(5)); let child = timer.spawn_with_timeout(time::Duration::from_secs(10)).await; tokio::time::sleep(time::Duration::from_secs(2)).await; assert!(!timer.is_timeout().await); assert!(!child.is_timeout().await); tokio::time::sleep(time::Duration::from_secs(4)).await; assert!(timer.is_timeout().await); assert!(child.is_timeout().await); assert_eq!(timer.error().await, Some(Error::ContextTimeout)); assert_eq!(child.error().await, Some(Error::ContextTimeout)); } #[tokio::test] async fn timer_handle_simple() { let timer = Timer::todo(); timer.handle(tokio::time::sleep(time::Duration::from_secs(1))).await.unwrap(); } #[tokio::test] async fn timer_handle_timeout() { let tc = TimeChecker::new(); let timer = Timer::with_timeout(time::Duration::from_secs(1)); let err = timer.handle(tokio::time::sleep(time::Duration::from_secs(10))).await .err().unwrap(); assert_eq!(err, Error::ContextTimeout); assert!(tc.not_exceed(time::Duration::from_millis(1300))); } #[tokio::test] async fn timer_handle_timeout_2() { let tc = TimeChecker::new(); let timer = Timer::with_timeout(time::Duration::from_secs(4)); let t1 = timer.clone(); let t2 = timer.clone(); let t1 = tokio::spawn(async move { t1.handle(tokio::time::sleep(time::Duration::from_secs(2))).await.unwrap(); }); let t2 = tokio::spawn(async move { let err = t2.handle(tokio::time::sleep(time::Duration::from_secs(10))).await.err().unwrap(); assert_eq!(err, Error::ContextTimeout); }); t1.await.unwrap(); t2.await.unwrap(); assert!(tc.not_exceed(time::Duration::from_millis(4300))); } #[tokio::test] async fn timer_partial_cancel() { let tc = TimeChecker::new(); let timer = Timer::with_timeout(time::Duration::from_secs(6)); let t1 = timer.clone(); let t2 = timer.clone(); let t1 = tokio::spawn(async move { t1.handle(tokio::time::sleep(time::Duration::from_secs(1))).await.unwrap(); }); let t2 = tokio::spawn(async move { let err = t2.handle(tokio::time::sleep(time::Duration::from_secs(8))).await.err().unwrap(); assert_eq!(err, Error::ContextCancelled); }); tokio::time::sleep(time::Duration::from_secs(3)).await; timer.cancel().await; t1.await.unwrap(); t2.await.unwrap(); assert!(tc.not_exceed(time::Duration::from_millis(3300))); } #[tokio::test] async fn timer_handle_result() { let timer = Timer::background(); mod def { #[derive(Debug, Clone)] pub struct MyError; impl From<context_async::Error> for MyError { fn from(_: context_async::Error) -> Self { MyError } } } async fn my_func() -> Result<u8, MyError> { Ok(1) } use def::*; timer.handle_result(my_func()).await.unwrap(); }