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 = 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]
42fn 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]
62fn 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")]
95async 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")]
125async 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]
152fn 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]
165async 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]
172async 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