#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", not(target_os = "wasi")))]
use std::sync::Arc;
use std::thread::sleep;
use tokio::time::Duration;
use tokio::runtime::Builder;
#[cfg(panic = "unwind")]
struct PanicOnDrop;
#[cfg(panic = "unwind")]
impl Drop for PanicOnDrop {
fn drop(&mut self) {
panic!("Well what did you expect would happen...");
}
}
#[test]
fn test_abort_without_panic_3157() {
let rt = Builder::new_multi_thread()
.enable_time()
.worker_threads(1)
.build()
.unwrap();
rt.block_on(async move {
let handle = tokio::spawn(async move { tokio::time::sleep(Duration::new(100, 0)).await });
tokio::time::sleep(Duration::from_millis(10)).await;
handle.abort();
let _ = handle.await;
});
}
#[test]
fn test_abort_without_panic_3662() {
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
struct DropCheck(Arc<AtomicBool>);
impl Drop for DropCheck {
fn drop(&mut self) {
self.0.store(true, Ordering::SeqCst);
}
}
let rt = Builder::new_current_thread().build().unwrap();
rt.block_on(async move {
let drop_flag = Arc::new(AtomicBool::new(false));
let drop_check = DropCheck(drop_flag.clone());
let j = tokio::spawn(async move {
let _drop_check = drop_check;
futures::future::pending::<()>().await;
});
let drop_flag2 = drop_flag.clone();
let task = std::thread::spawn(move || {
assert!(!drop_flag2.load(Ordering::SeqCst));
j.abort();
j
})
.join()
.unwrap();
let result = task.await;
assert!(drop_flag.load(Ordering::SeqCst));
assert!(result.unwrap_err().is_cancelled());
let i = tokio::spawn(async move {
tokio::task::yield_now().await;
});
i.await.unwrap();
});
}
#[test]
fn remote_abort_local_set_3929() {
struct DropCheck {
created_on: std::thread::ThreadId,
not_send: std::marker::PhantomData<*const ()>,
}
impl DropCheck {
fn new() -> Self {
Self {
created_on: std::thread::current().id(),
not_send: std::marker::PhantomData,
}
}
}
impl Drop for DropCheck {
fn drop(&mut self) {
if std::thread::current().id() != self.created_on {
panic!("non-Send value dropped in another thread!");
}
}
}
let rt = Builder::new_current_thread().build().unwrap();
let local = tokio::task::LocalSet::new();
let check = DropCheck::new();
let jh = local.spawn_local(async move {
futures::future::pending::<()>().await;
drop(check);
});
let jh2 = std::thread::spawn(move || {
sleep(Duration::from_millis(10));
jh.abort();
});
rt.block_on(local);
jh2.join().unwrap();
}
#[test]
fn test_abort_wakes_task_3964() {
let rt = Builder::new_current_thread().enable_time().build().unwrap();
rt.block_on(async move {
let notify_dropped = Arc::new(());
let weak_notify_dropped = Arc::downgrade(¬ify_dropped);
let handle = tokio::spawn(async move {
let _notify_dropped = notify_dropped;
tokio::time::sleep(Duration::new(100, 0)).await
});
tokio::time::sleep(Duration::from_millis(10)).await;
handle.abort();
drop(handle);
tokio::time::sleep(Duration::from_millis(10)).await;
assert!(weak_notify_dropped.upgrade().is_none());
});
}
#[test]
#[cfg(panic = "unwind")]
fn test_abort_task_that_panics_on_drop_contained() {
let rt = Builder::new_current_thread().enable_time().build().unwrap();
rt.block_on(async move {
let handle = tokio::spawn(async move {
let _panic_dropped = PanicOnDrop;
tokio::time::sleep(Duration::new(100, 0)).await
});
tokio::time::sleep(Duration::from_millis(10)).await;
handle.abort();
drop(handle);
tokio::time::sleep(Duration::from_millis(10)).await;
});
}
#[test]
#[cfg(panic = "unwind")]
fn test_abort_task_that_panics_on_drop_returned() {
let rt = Builder::new_current_thread().enable_time().build().unwrap();
rt.block_on(async move {
let handle = tokio::spawn(async move {
let _panic_dropped = PanicOnDrop;
tokio::time::sleep(Duration::new(100, 0)).await
});
tokio::time::sleep(Duration::from_millis(10)).await;
handle.abort();
assert!(handle.await.unwrap_err().is_panic());
});
}
#[test]
#[cfg(panic = "unwind")]
fn test_join_error_display() {
let rt = Builder::new_current_thread().build().unwrap();
rt.block_on(async move {
let join_err = tokio::spawn(async move {
let value = 1234;
panic!("Format-args payload: {value}")
})
.await
.unwrap_err();
let join_err_str = join_err.to_string();
assert!(
join_err_str.starts_with("task ")
&& join_err_str.ends_with(" panicked with message \"Format-args payload: 1234\""),
"Unexpected join_err_str {join_err_str:?}"
);
let join_err = tokio::spawn(async move { panic!("Const payload") })
.await
.unwrap_err();
let join_err_str = join_err.to_string();
assert!(
join_err_str.starts_with("task ")
&& join_err_str.ends_with(" panicked with message \"Const payload\""),
"Unexpected join_err_str {join_err_str:?}"
);
let join_err = tokio::spawn(async move { std::panic::panic_any(1234i32) })
.await
.unwrap_err();
let join_err_str = join_err.to_string();
assert!(
join_err_str.starts_with("task ") && join_err_str.ends_with(" panicked"),
"Unexpected join_err_str {join_err_str:?}"
);
});
}
#[test]
#[cfg(panic = "unwind")]
fn test_join_error_debug() {
let rt = Builder::new_current_thread().build().unwrap();
rt.block_on(async move {
let join_err = tokio::spawn(async move {
let value = 1234;
panic!("Format-args payload: {value}")
})
.await
.unwrap_err();
let join_err_str = format!("{join_err:?}");
assert!(
join_err_str.starts_with("JoinError::Panic(Id(")
&& join_err_str.ends_with("), \"Format-args payload: 1234\", ...)"),
"Unexpected join_err_str {join_err_str:?}"
);
let join_err = tokio::spawn(async move { panic!("Const payload") })
.await
.unwrap_err();
let join_err_str = format!("{join_err:?}");
assert!(
join_err_str.starts_with("JoinError::Panic(Id(")
&& join_err_str.ends_with("), \"Const payload\", ...)"),
"Unexpected join_err_str {join_err_str:?}"
);
let join_err = tokio::spawn(async move { std::panic::panic_any(1234i32) })
.await
.unwrap_err();
let join_err_str = format!("{join_err:?}");
assert!(
join_err_str.starts_with("JoinError::Panic(Id(") && join_err_str.ends_with("), ...)"),
"Unexpected join_err_str {join_err_str:?}"
);
});
}