• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #![warn(rust_2018_idioms)]
2 #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support panic recovery
3 
4 use parking_lot::{const_mutex, Mutex};
5 use std::error::Error;
6 use std::panic;
7 use std::sync::Arc;
8 use tokio::runtime::Runtime;
9 use tokio::sync::mpsc::channel;
10 use tokio::time::{Duration, Instant};
11 use tokio_test::task;
12 use tokio_util::io::SyncIoBridge;
13 use tokio_util::sync::PollSender;
14 use tokio_util::task::LocalPoolHandle;
15 use tokio_util::time::DelayQueue;
16 
17 // Taken from tokio-util::time::wheel, if that changes then
18 const MAX_DURATION_MS: u64 = (1 << (36)) - 1;
19 
test_panic<Func: FnOnce() + panic::UnwindSafe>(func: Func) -> Option<String>20 fn test_panic<Func: FnOnce() + panic::UnwindSafe>(func: Func) -> Option<String> {
21     static PANIC_MUTEX: Mutex<()> = const_mutex(());
22 
23     {
24         let _guard = PANIC_MUTEX.lock();
25         let panic_file: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None));
26 
27         let prev_hook = panic::take_hook();
28         {
29             let panic_file = panic_file.clone();
30             panic::set_hook(Box::new(move |panic_info| {
31                 let panic_location = panic_info.location().unwrap();
32                 panic_file
33                     .lock()
34                     .clone_from(&Some(panic_location.file().to_string()));
35             }));
36         }
37 
38         let result = panic::catch_unwind(func);
39         // Return to the previously set panic hook (maybe default) so that we get nice error
40         // messages in the tests.
41         panic::set_hook(prev_hook);
42 
43         if result.is_err() {
44             panic_file.lock().clone()
45         } else {
46             None
47         }
48     }
49 }
50 
51 #[test]
sync_bridge_new_panic_caller() -> Result<(), Box<dyn Error>>52 fn sync_bridge_new_panic_caller() -> Result<(), Box<dyn Error>> {
53     let panic_location_file = test_panic(|| {
54         let _ = SyncIoBridge::new(tokio::io::empty());
55     });
56 
57     // The panic location should be in this file
58     assert_eq!(&panic_location_file.unwrap(), file!());
59 
60     Ok(())
61 }
62 
63 #[test]
poll_sender_send_item_panic_caller() -> Result<(), Box<dyn Error>>64 fn poll_sender_send_item_panic_caller() -> Result<(), Box<dyn Error>> {
65     let panic_location_file = test_panic(|| {
66         let (send, _) = channel::<u32>(3);
67         let mut send = PollSender::new(send);
68 
69         let _ = send.send_item(42);
70     });
71 
72     // The panic location should be in this file
73     assert_eq!(&panic_location_file.unwrap(), file!());
74 
75     Ok(())
76 }
77 
78 #[test]
79 
local_pool_handle_new_panic_caller() -> Result<(), Box<dyn Error>>80 fn local_pool_handle_new_panic_caller() -> Result<(), Box<dyn Error>> {
81     let panic_location_file = test_panic(|| {
82         let _ = LocalPoolHandle::new(0);
83     });
84 
85     // The panic location should be in this file
86     assert_eq!(&panic_location_file.unwrap(), file!());
87 
88     Ok(())
89 }
90 
91 #[test]
92 
local_pool_handle_spawn_pinned_by_idx_panic_caller() -> Result<(), Box<dyn Error>>93 fn local_pool_handle_spawn_pinned_by_idx_panic_caller() -> Result<(), Box<dyn Error>> {
94     let panic_location_file = test_panic(|| {
95         let rt = basic();
96 
97         rt.block_on(async {
98             let handle = LocalPoolHandle::new(2);
99             handle.spawn_pinned_by_idx(|| async { "test" }, 3);
100         });
101     });
102 
103     // The panic location should be in this file
104     assert_eq!(&panic_location_file.unwrap(), file!());
105 
106     Ok(())
107 }
108 #[test]
delay_queue_insert_at_panic_caller() -> Result<(), Box<dyn Error>>109 fn delay_queue_insert_at_panic_caller() -> Result<(), Box<dyn Error>> {
110     let panic_location_file = test_panic(|| {
111         let rt = basic();
112         rt.block_on(async {
113             let mut queue = task::spawn(DelayQueue::with_capacity(3));
114 
115             //let st = std::time::Instant::from(SystemTime::UNIX_EPOCH);
116             let _k = queue.insert_at(
117                 "1",
118                 Instant::now() + Duration::from_millis(MAX_DURATION_MS + 1),
119             );
120         });
121     });
122 
123     // The panic location should be in this file
124     assert_eq!(&panic_location_file.unwrap(), file!());
125 
126     Ok(())
127 }
128 
129 #[test]
delay_queue_insert_panic_caller() -> Result<(), Box<dyn Error>>130 fn delay_queue_insert_panic_caller() -> Result<(), Box<dyn Error>> {
131     let panic_location_file = test_panic(|| {
132         let rt = basic();
133         rt.block_on(async {
134             let mut queue = task::spawn(DelayQueue::with_capacity(3));
135 
136             let _k = queue.insert("1", Duration::from_millis(MAX_DURATION_MS + 1));
137         });
138     });
139 
140     // The panic location should be in this file
141     assert_eq!(&panic_location_file.unwrap(), file!());
142 
143     Ok(())
144 }
145 
146 #[test]
delay_queue_remove_panic_caller() -> Result<(), Box<dyn Error>>147 fn delay_queue_remove_panic_caller() -> Result<(), Box<dyn Error>> {
148     let panic_location_file = test_panic(|| {
149         let rt = basic();
150         rt.block_on(async {
151             let mut queue = task::spawn(DelayQueue::with_capacity(3));
152 
153             let key = queue.insert_at("1", Instant::now());
154             queue.remove(&key);
155             queue.remove(&key);
156         });
157     });
158 
159     // The panic location should be in this file
160     assert_eq!(&panic_location_file.unwrap(), file!());
161 
162     Ok(())
163 }
164 
165 #[test]
delay_queue_reset_at_panic_caller() -> Result<(), Box<dyn Error>>166 fn delay_queue_reset_at_panic_caller() -> Result<(), Box<dyn Error>> {
167     let panic_location_file = test_panic(|| {
168         let rt = basic();
169         rt.block_on(async {
170             let mut queue = task::spawn(DelayQueue::with_capacity(3));
171 
172             let key = queue.insert_at("1", Instant::now());
173             queue.reset_at(
174                 &key,
175                 Instant::now() + Duration::from_millis(MAX_DURATION_MS + 1),
176             );
177         });
178     });
179 
180     // The panic location should be in this file
181     assert_eq!(&panic_location_file.unwrap(), file!());
182 
183     Ok(())
184 }
185 
186 #[test]
delay_queue_reset_panic_caller() -> Result<(), Box<dyn Error>>187 fn delay_queue_reset_panic_caller() -> Result<(), Box<dyn Error>> {
188     let panic_location_file = test_panic(|| {
189         let rt = basic();
190         rt.block_on(async {
191             let mut queue = task::spawn(DelayQueue::with_capacity(3));
192 
193             let key = queue.insert_at("1", Instant::now());
194             queue.reset(&key, Duration::from_millis(MAX_DURATION_MS + 1));
195         });
196     });
197 
198     // The panic location should be in this file
199     assert_eq!(&panic_location_file.unwrap(), file!());
200 
201     Ok(())
202 }
203 
204 #[test]
delay_queue_reserve_panic_caller() -> Result<(), Box<dyn Error>>205 fn delay_queue_reserve_panic_caller() -> Result<(), Box<dyn Error>> {
206     let panic_location_file = test_panic(|| {
207         let rt = basic();
208         rt.block_on(async {
209             let mut queue = task::spawn(DelayQueue::<u32>::with_capacity(3));
210 
211             queue.reserve((1 << 30) as usize);
212         });
213     });
214 
215     // The panic location should be in this file
216     assert_eq!(&panic_location_file.unwrap(), file!());
217 
218     Ok(())
219 }
220 
basic() -> Runtime221 fn basic() -> Runtime {
222     tokio::runtime::Builder::new_current_thread()
223         .enable_all()
224         .build()
225         .unwrap()
226 }
227