Created
December 1, 2024 19:15
-
-
Save jberkenbilt/24b64bc0f61c401d39727fc64394eeb3 to your computer and use it in GitHub Desktop.
Go to Rust: 04 tokio runtime tests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use super::*; | |
use crate::{Locker, TokioRuntime}; | |
use std::sync::Arc; | |
use std::time::Duration; | |
use tokio::sync::oneshot; | |
use tokio::task; | |
async fn generic_thing<M>(m: &M) | |
where | |
M: AsyncRwLock<i32>, | |
{ | |
{ | |
// Hold lock across an await point. We don't get warnings for this, and | |
// as long as RwLock is implemented using an async-aware RwLock, we're | |
// fine. | |
let lock = m.read().await; | |
// non-Send Future | |
async move { std::ptr::null::<*const ()>() }.await; | |
assert_eq!(*lock, 3); | |
} | |
{ | |
let mut lock = m.write().await; | |
// non-Send Future | |
async move { std::ptr::null::<*const ()>() }.await; | |
*lock = 4; | |
} | |
{ | |
let lock = m.read().await; | |
assert_eq!(*lock, 4); | |
async move {}.await; | |
} | |
} | |
#[tokio::test(flavor = "current_thread")] | |
async fn test_basic() { | |
let m1 = Arc::new(TokioRuntime::new_lock(3)); | |
generic_thing(m1.as_ref()).await; | |
let m2 = m1.clone(); | |
assert_eq!(*m1.read().await, 4); | |
let h = task::spawn(async move { | |
let mut lock = m2.write().await; | |
// non-Send Future | |
async move { std::ptr::null::<*const ()>() }.await; | |
*lock = 5; | |
1 | |
}); | |
assert_eq!(1, h.await.unwrap()); | |
let lock = m1.read().await; | |
assert_eq!(*lock, 5); | |
} | |
#[tokio::test(flavor = "current_thread")] | |
async fn test_lock() { | |
// Exercise non-trivial case of waiting for a lock. | |
let m1 = Arc::new(TokioRuntime::new_lock(5)); | |
let (tx, rx) = oneshot::channel::<()>(); | |
let m2 = m1.clone(); | |
let h1 = task::spawn(async move { | |
// Grab the lock first, then signal to the other task. | |
let mut lock = m2.write().await; | |
tx.send(()).unwrap(); | |
// We got the lock first. The other side can't progress. | |
tokio::time::sleep(Duration::from_millis(10)).await; | |
assert_eq!(*lock, 5); | |
*lock = 10; | |
// When we finish, we automatically release the lock. | |
}); | |
let m2 = m1.clone(); | |
let h2 = task::spawn(async move { | |
// Wait for the first the channel, and then grab the lock. | |
rx.await.unwrap(); | |
// Try to get the lock. This will "block" (yield to the runtime) until | |
// the lock is available. | |
let mut lock = m2.write().await; | |
// The other side has finished. | |
assert_eq!(*lock, 10); | |
*lock = 11; | |
}); | |
// Wait for the jobs to finish. | |
h1.await.unwrap(); | |
h2.await.unwrap(); | |
let lock = m1.read().await; | |
assert_eq!(*lock, 11); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment