use core::ops::Range; use core::time::Duration; use safina_async_test::async_test; use safina_sync::Mutex; use safina_timer::sleep_for; use std::sync::Arc; use std::time::Instant; /// # Panics /// Panics if the time elapsed since `before` is not in `range_ms`. pub fn expect_elapsed(before: Instant, range_ms: Range) { assert!(!range_ms.is_empty(), "invalid range {:?}", range_ms); let elapsed = before.elapsed(); let duration_range = Duration::from_millis(range_ms.start)..Duration::from_millis(range_ms.end); assert!( duration_range.contains(&elapsed), "{:?} elapsed, out of range {:?}", elapsed, duration_range ); } #[async_test] async fn should_unlock_immediately() { let before = Instant::now(); let counter = Mutex::new(0_u8); { let mut guard = counter.lock().await; *guard += 1; } let guard = counter.lock().await; assert_eq!(1_u8, *guard); expect_elapsed(before, 0..10); } #[async_test] async fn unlocking_wakes_waiters() { let before = Instant::now(); let counter = Arc::new(Mutex::new(0_u8)); let counter_clone = counter.clone(); safina_executor::spawn(async move { let mut guard = counter_clone.lock().await; *guard += 1; }); // Delay so other task can get the lock sleep_for(Duration::from_millis(100)).await; let guard = counter.lock().await; assert_eq!(1_u8, *guard); expect_elapsed(before, 100..200); } #[async_test] async fn should_handle_many_waiters() { const NUM_WAITERS: u32 = 10_000; let before = Instant::now(); let counter = Arc::new(Mutex::new(0_u32)); let mut receivers = Vec::new(); for _ in 0..NUM_WAITERS { let counter_clone = counter.clone(); let (sender, receiver) = std::sync::mpsc::channel::<()>(); receivers.push(receiver); safina_executor::spawn(async move { { let mut guard = counter_clone.lock().await; *guard += 1; } sender.send(()).unwrap(); }); } for receiver in receivers { receiver.recv().unwrap(); } let guard = counter.lock().await; assert_eq!(NUM_WAITERS, *guard); expect_elapsed(before, 0..5000); }