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] |
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] |
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" )] |
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" )] |
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] |
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 ] |
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 ] |
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 | |