1 #![warn(rust_2018_idioms)]
2 #![cfg(feature = "sync")]
3 
4 #[cfg(all(target_family = "wasm", not(target_os = "wasi")))]
5 use wasm_bindgen_test::wasm_bindgen_test as test;
6 #[cfg(all(target_family = "wasm", not(target_os = "wasi")))]
7 use wasm_bindgen_test::wasm_bindgen_test as maybe_tokio_test;
8 
9 #[cfg(not(all(target_family = "wasm", not(target_os = "wasi"))))]
10 use tokio::test as maybe_tokio_test;
11 
12 use tokio::sync::Mutex;
13 use tokio_test::task::spawn;
14 use tokio_test::{assert_pending, assert_ready};
15 
16 use std::sync::Arc;
17 
18 #[test]
straight_execution()19 fn straight_execution() {
20     let l = Mutex::new(100);
21 
22     {
23         let mut t = spawn(l.lock());
24         let mut g = assert_ready!(t.poll());
25         assert_eq!(&*g, &100);
26         *g = 99;
27     }
28     {
29         let mut t = spawn(l.lock());
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());
36         let g = assert_ready!(t.poll());
37         assert_eq!(&*g, &98);
38     }
39 }
40 
41 #[test]
readiness()42 fn readiness() {
43     let l1 = Arc::new(Mutex::new(100));
44     let l2 = Arc::clone(&l1);
45     let mut t1 = spawn(l1.lock());
46     let mut t2 = spawn(l2.lock());
47 
48     let g = assert_ready!(t1.poll());
49 
50     // We can't now acquire the lease since it's already held in g
51     assert_pending!(t2.poll());
52 
53     // But once g unlocks, we can acquire it
54     drop(g);
55     assert!(t2.is_woken());
56     let _t2 = assert_ready!(t2.poll());
57 }
58 
59 /*
60 #[test]
61 #[ignore]
62 fn lock() {
63     let mut lock = Mutex::new(false);
64 
65     let mut lock2 = lock.clone();
66     std::thread::spawn(move || {
67         let l = lock2.lock();
68         pin_mut!(l);
69 
70         let mut task = MockTask::new();
71         let mut g = assert_ready!(task.poll(&mut l));
72         std::thread::sleep(std::time::Duration::from_millis(500));
73         *g = true;
74         drop(g);
75     });
76 
77     std::thread::sleep(std::time::Duration::from_millis(50));
78     let mut task = MockTask::new();
79     let l = lock.lock();
80     pin_mut!(l);
81 
82     assert_pending!(task.poll(&mut l));
83 
84     std::thread::sleep(std::time::Duration::from_millis(500));
85     assert!(task.is_woken());
86     let result = assert_ready!(task.poll(&mut l));
87     assert!(*result);
88 }
89 */
90 
91 /// Ensure a mutex is unlocked if a future holding the lock
92 /// is aborted prematurely.
93 #[tokio::test]
94 #[cfg(feature = "full")]
aborted_future_1()95 async fn aborted_future_1() {
96     use std::time::Duration;
97     use tokio::time::{interval, timeout};
98 
99     let m1: Arc<Mutex<usize>> = Arc::new(Mutex::new(0));
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             let iv = interval(Duration::from_millis(1000));
105             tokio::pin!(iv);
106             let _g = m2.lock().await;
107             iv.as_mut().tick().await;
108             iv.as_mut().tick().await;
109         })
110         .await
111         .unwrap_err();
112     }
113     // This should succeed as there is no lock left for the mutex.
114     timeout(Duration::from_millis(1u64), async move {
115         let _g = m1.lock().await;
116     })
117     .await
118     .expect("Mutex is locked");
119 }
120 
121 /// This test is similar to `aborted_future_1` but this time the
122 /// aborted future is waiting for the lock.
123 #[tokio::test]
124 #[cfg(feature = "full")]
aborted_future_2()125 async fn aborted_future_2() {
126     use std::time::Duration;
127     use tokio::time::timeout;
128 
129     let m1: Arc<Mutex<usize>> = Arc::new(Mutex::new(0));
130     {
131         // Lock mutex
132         let _lock = m1.lock().await;
133         {
134             let m2 = m1.clone();
135             // Try to lock mutex in a future that is aborted prematurely
136             timeout(Duration::from_millis(1u64), async move {
137                 let _g = m2.lock().await;
138             })
139             .await
140             .unwrap_err();
141         }
142     }
143     // This should succeed as there is no lock left for the mutex.
144     timeout(Duration::from_millis(1u64), async move {
145         let _g = m1.lock().await;
146     })
147     .await
148     .expect("Mutex is locked");
149 }
150 
151 #[test]
try_lock()152 fn try_lock() {
153     let m: Mutex<usize> = Mutex::new(0);
154     {
155         let g1 = m.try_lock();
156         assert!(g1.is_ok());
157         let g2 = m.try_lock();
158         assert!(g2.is_err());
159     }
160     let g3 = m.try_lock();
161     assert!(g3.is_ok());
162 }
163 
164 #[maybe_tokio_test]
debug_format()165 async fn debug_format() {
166     let s = "debug";
167     let m = Mutex::new(s.to_string());
168     assert_eq!(format!("{s:?}"), format!("{:?}", m.lock().await));
169 }
170 
171 #[maybe_tokio_test]
mutex_debug()172 async fn mutex_debug() {
173     let s = "data";
174     let m = Mutex::new(s.to_string());
175     assert_eq!(format!("{m:?}"), r#"Mutex { data: "data" }"#);
176     let _guard = m.lock().await;
177     assert_eq!(format!("{m:?}"), r#"Mutex { data: <locked> }"#)
178 }
179