1#![warn(rust_2018_idioms)]
2#![cfg(feature = "sync")]
3
4#[cfg(all(target_family = "wasm", not(target_os = "wasi")))]
5use wasm_bindgen_test::wasm_bindgen_test as test;
6#[cfg(all(target_family = "wasm", not(target_os = "wasi")))]
7use wasm_bindgen_test::wasm_bindgen_test as maybe_tokio_test;
8
9#[cfg(not(all(target_family = "wasm", not(target_os = "wasi"))))]
10use tokio::test as maybe_tokio_test;
11
12use tokio::sync::Mutex;
13use tokio_test::task::spawn;
14use tokio_test::{assert_pending, assert_ready};
15
16use std::sync::Arc;
17
18#[test]
19fn straight_execution() {
20 let l = Arc::new(Mutex::new(100));
21
22 {
23 let mut t = spawn(l.clone().lock_owned());
24 let mut g = assert_ready!(t.poll());
25 assert_eq!(&*g, &100);
26 *g = 99;
27 }
28 {
29 let mut t = spawn(l.clone().lock_owned());
30 let mut g = assert_ready!(t.poll());
31 assert_eq!(&*g, &99);
32 *g = 98;
33 }
34 {
35 let mut t = spawn(l.lock_owned());
36 let g = assert_ready!(t.poll());
37 assert_eq!(&*g, &98);
38 }
39}
40
41#[test]
42fn readiness() {
43 let l = Arc::new(Mutex::new(100));
44 let mut t1 = spawn(l.clone().lock_owned());
45 let mut t2 = spawn(l.lock_owned());
46
47 let g = assert_ready!(t1.poll());
48
49 // We can't now acquire the lease since it's already held in g
50 assert_pending!(t2.poll());
51
52 // But once g unlocks, we can acquire it
53 drop(g);
54 assert!(t2.is_woken());
55 assert_ready!(t2.poll());
56}
57
58/// Ensure a mutex is unlocked if a future holding the lock
59/// is aborted prematurely.
60#[tokio::test]
61#[cfg(feature = "full")]
62async fn aborted_future_1() {
63 use std::time::Duration;
64 use tokio::time::{interval, timeout};
65
66 let m1: Arc<Mutex<usize>> = Arc::new(Mutex::new(0));
67 {
68 let m2 = m1.clone();
69 // Try to lock mutex in a future that is aborted prematurely
70 timeout(Duration::from_millis(1u64), async move {
71 let iv = interval(Duration::from_millis(1000));
72 tokio::pin!(iv);
73 m2.lock_owned().await;
74 iv.as_mut().tick().await;
75 iv.as_mut().tick().await;
76 })
77 .await
78 .unwrap_err();
79 }
80 // This should succeed as there is no lock left for the mutex.
81 timeout(Duration::from_millis(1u64), async move {
82 m1.lock_owned().await;
83 })
84 .await
85 .expect("Mutex is locked");
86}
87
88/// This test is similar to `aborted_future_1` but this time the
89/// aborted future is waiting for the lock.
90#[tokio::test]
91#[cfg(feature = "full")]
92async fn aborted_future_2() {
93 use std::time::Duration;
94 use tokio::time::timeout;
95
96 let m1: Arc<Mutex<usize>> = Arc::new(Mutex::new(0));
97 {
98 // Lock mutex
99 let _lock = m1.clone().lock_owned().await;
100 {
101 let m2 = m1.clone();
102 // Try to lock mutex in a future that is aborted prematurely
103 timeout(Duration::from_millis(1u64), async move {
104 m2.lock_owned().await;
105 })
106 .await
107 .unwrap_err();
108 }
109 }
110 // This should succeed as there is no lock left for the mutex.
111 timeout(Duration::from_millis(1u64), async move {
112 m1.lock_owned().await;
113 })
114 .await
115 .expect("Mutex is locked");
116}
117
118#[test]
119fn try_lock_owned() {
120 let m: Arc<Mutex<usize>> = Arc::new(Mutex::new(0));
121 {
122 let g1 = m.clone().try_lock_owned();
123 assert!(g1.is_ok());
124 let g2 = m.clone().try_lock_owned();
125 assert!(g2.is_err());
126 }
127 let g3 = m.try_lock_owned();
128 assert!(g3.is_ok());
129}
130
131#[maybe_tokio_test]
132async fn debug_format() {
133 let s = "debug";
134 let m = Arc::new(Mutex::new(s.to_string()));
135 assert_eq!(format!("{:?}", s), format!("{:?}", m.lock_owned().await));
136}
137