mirror of
https://github.com/tokio-rs/tokio.git
synced 2025-09-25 12:00:35 +00:00
243 lines
6.7 KiB
Rust
243 lines
6.7 KiB
Rust
#![warn(rust_2018_idioms)]
|
|
#![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support panic recovery
|
|
#![cfg(panic = "unwind")]
|
|
|
|
use parking_lot::{const_mutex, Mutex};
|
|
use std::error::Error;
|
|
use std::panic;
|
|
use std::sync::Arc;
|
|
use tokio::runtime::Runtime;
|
|
use tokio::sync::mpsc::channel;
|
|
use tokio::time::{Duration, Instant};
|
|
use tokio_test::task;
|
|
use tokio_util::io::SyncIoBridge;
|
|
use tokio_util::sync::PollSender;
|
|
use tokio_util::task::LocalPoolHandle;
|
|
use tokio_util::time::DelayQueue;
|
|
|
|
// Taken from tokio-util::time::wheel, if that changes then
|
|
const MAX_DURATION_MS: u64 = (1 << (36)) - 1;
|
|
|
|
fn test_panic<Func: FnOnce() + panic::UnwindSafe>(func: Func) -> Option<String> {
|
|
static PANIC_MUTEX: Mutex<()> = const_mutex(());
|
|
|
|
{
|
|
let _guard = PANIC_MUTEX.lock();
|
|
let panic_file: Arc<Mutex<Option<String>>> = Arc::new(Mutex::new(None));
|
|
|
|
let prev_hook = panic::take_hook();
|
|
{
|
|
let panic_file = panic_file.clone();
|
|
panic::set_hook(Box::new(move |panic_info| {
|
|
let panic_location = panic_info.location().unwrap();
|
|
panic_file
|
|
.lock()
|
|
.clone_from(&Some(panic_location.file().to_string()));
|
|
}));
|
|
}
|
|
|
|
let result = panic::catch_unwind(func);
|
|
// Return to the previously set panic hook (maybe default) so that we get nice error
|
|
// messages in the tests.
|
|
panic::set_hook(prev_hook);
|
|
|
|
if result.is_err() {
|
|
panic_file.lock().clone()
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn sync_bridge_new_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
let panic_location_file = test_panic(|| {
|
|
let _ = SyncIoBridge::new(tokio::io::empty());
|
|
});
|
|
|
|
// The panic location should be in this file
|
|
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn poll_sender_send_item_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
let panic_location_file = test_panic(|| {
|
|
let (send, _) = channel::<u32>(3);
|
|
let mut send = PollSender::new(send);
|
|
|
|
let _ = send.send_item(42);
|
|
});
|
|
|
|
// The panic location should be in this file
|
|
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn local_pool_handle_new_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
let panic_location_file = test_panic(|| {
|
|
let _ = LocalPoolHandle::new(0);
|
|
});
|
|
|
|
// The panic location should be in this file
|
|
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn local_pool_handle_spawn_pinned_by_idx_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
let panic_location_file = test_panic(|| {
|
|
let rt = basic();
|
|
|
|
rt.block_on(async {
|
|
let handle = LocalPoolHandle::new(2);
|
|
handle.spawn_pinned_by_idx(|| async { "test" }, 3);
|
|
});
|
|
});
|
|
|
|
// The panic location should be in this file
|
|
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
|
|
Ok(())
|
|
}
|
|
#[test]
|
|
fn delay_queue_insert_at_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
let panic_location_file = test_panic(|| {
|
|
let rt = basic();
|
|
rt.block_on(async {
|
|
let mut queue = task::spawn(DelayQueue::with_capacity(3));
|
|
|
|
//let st = std::time::Instant::from(SystemTime::UNIX_EPOCH);
|
|
let _k = queue.insert_at(
|
|
"1",
|
|
Instant::now() + Duration::from_millis(MAX_DURATION_MS + 1),
|
|
);
|
|
});
|
|
});
|
|
|
|
// The panic location should be in this file
|
|
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn delay_queue_insert_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
let panic_location_file = test_panic(|| {
|
|
let rt = basic();
|
|
rt.block_on(async {
|
|
let mut queue = task::spawn(DelayQueue::with_capacity(3));
|
|
|
|
let _k = queue.insert("1", Duration::from_millis(MAX_DURATION_MS + 1));
|
|
});
|
|
});
|
|
|
|
// The panic location should be in this file
|
|
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn delay_queue_remove_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
let panic_location_file = test_panic(|| {
|
|
let rt = basic();
|
|
rt.block_on(async {
|
|
let mut queue = task::spawn(DelayQueue::with_capacity(3));
|
|
|
|
let key = queue.insert_at("1", Instant::now());
|
|
queue.remove(&key);
|
|
queue.remove(&key);
|
|
});
|
|
});
|
|
|
|
// The panic location should be in this file
|
|
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn delay_queue_reset_at_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
let panic_location_file = test_panic(|| {
|
|
let rt = basic();
|
|
rt.block_on(async {
|
|
let mut queue = task::spawn(DelayQueue::with_capacity(3));
|
|
|
|
let key = queue.insert_at("1", Instant::now());
|
|
queue.reset_at(
|
|
&key,
|
|
Instant::now() + Duration::from_millis(MAX_DURATION_MS + 1),
|
|
);
|
|
});
|
|
});
|
|
|
|
// The panic location should be in this file
|
|
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn delay_queue_reset_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
let panic_location_file = test_panic(|| {
|
|
let rt = basic();
|
|
rt.block_on(async {
|
|
let mut queue = task::spawn(DelayQueue::with_capacity(3));
|
|
|
|
let key = queue.insert_at("1", Instant::now());
|
|
queue.reset(&key, Duration::from_millis(MAX_DURATION_MS + 1));
|
|
});
|
|
});
|
|
|
|
// The panic location should be in this file
|
|
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn delay_queue_reserve_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
let panic_location_file = test_panic(|| {
|
|
let rt = basic();
|
|
rt.block_on(async {
|
|
let mut queue = task::spawn(DelayQueue::<u32>::with_capacity(3));
|
|
|
|
queue.reserve((1 << 30) as usize);
|
|
});
|
|
});
|
|
|
|
// The panic location should be in this file
|
|
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn future_ext_to_panic_caller() -> Result<(), Box<dyn Error>> {
|
|
use tokio::{sync::oneshot, time::Duration};
|
|
use tokio_util::future::FutureExt;
|
|
|
|
let panic_location_file = test_panic(|| {
|
|
let (_tx, rx) = oneshot::channel::<()>();
|
|
// this panics because there is no runtime available
|
|
let _res = rx.timeout(Duration::from_millis(10));
|
|
});
|
|
|
|
// The panic location should be in this file
|
|
assert_eq!(&panic_location_file.unwrap(), file!());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn basic() -> Runtime {
|
|
tokio::runtime::Builder::new_current_thread()
|
|
.enable_all()
|
|
.build()
|
|
.unwrap()
|
|
}
|