let out = rt.block_on(async { assert_ok!(rx.await) });
assert_eq!(out, "hello");
}
#[test] fn no_extra_poll() { use pin_project_lite::pin_project; use std::pin::Pin; use std::sync::{
atomic::{AtomicUsize, Ordering::SeqCst},
Arc,
}; use std::task::{Context, Poll}; use tokio_stream::{Stream, StreamExt};
impl Drop for ContextOnDrop { fn drop(&mutself) { if tokio::runtime::Handle::try_current().is_ok() {
SUCCESS.store(true, Ordering::SeqCst);
}
}
}
let rt = rt();
rt.spawn(ContextOnDrop);
drop(rt);
assert!(SUCCESS.load(Ordering::SeqCst));
}
#[test] #[cfg_attr(target_os = "wasi", ignore = "Wasi does not support panic recovery")] #[should_panic(expected = "boom")] fn wake_in_drop_after_panic() { struct WakeOnDrop(Option<oneshot::Sender<()>>);
impl Drop for WakeOnDrop { fn drop(&mutself) { let _ = self.0.take().unwrap().send(());
}
}
let rt = rt();
let (tx1, rx1) = oneshot::channel::<()>(); let (tx2, rx2) = oneshot::channel::<()>();
// Spawn two tasks. We don't know the order in which they are dropped, so we // make both tasks identical. When the first task is dropped, we wake up the // second task. This ensures that we trigger a wakeup on a live task while // handling the "boom" panic, no matter the order in which the tasks are // dropped.
rt.spawn(asyncmove { let _wake_on_drop = WakeOnDrop(Some(tx2)); let _ = rx1.await;
unreachable!()
});
rt.spawn(asyncmove { let _wake_on_drop = WakeOnDrop(Some(tx1)); let _ = rx2.await;
unreachable!()
});
cfg_metrics! { let metrics = rt.metrics();
drop(rt);
assert_eq!(1, metrics.remote_schedule_count());
letmut local = 0; for i in0..metrics.num_workers() {
local += metrics.worker_local_schedule_count(i);
}
assert_eq!(1, local);
}
}
#[test] #[cfg_attr(target_os = "wasi", ignore = "Wasi does not support panic recovery")] #[should_panic(
expected = "A Tokio 1.x context was found, but timers are disabled. Call `enable_time` on the runtime builder to enable timers."
)] fn timeout_panics_when_no_time_handle() { let rt = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
rt.block_on(async { let (_tx, rx) = oneshot::channel::<()>(); let dur = Duration::from_millis(20); let _ = timeout(dur, rx).await;
});
}
#[cfg(tokio_unstable)] mod unstable { use tokio::runtime::{Builder, RngSeed, UnhandledPanic};
#[test] #[should_panic(
expected = "a spawned task panicked and the runtime is configured to shut down on unhandled panic"
)] fn shutdown_on_panic() { let rt = Builder::new_current_thread()
.unhandled_panic(UnhandledPanic::ShutdownRuntime)
.build()
.unwrap();
let task = rt1.spawn(async {}); let res = futures::executor::block_on(task);
assert!(res.is_err());
}
#[test] #[cfg_attr(target_os = "wasi", ignore = "Wasi does not support panic recovery")] fn shutdown_all_concurrent_block_on() { const N: usize = 2; use std::sync::{mpsc, Arc};
let rt = Builder::new_current_thread()
.unhandled_panic(UnhandledPanic::ShutdownRuntime)
.build()
.unwrap();
let rt = Arc::new(rt); letmut ths = vec![]; let (tx, rx) = mpsc::channel();
for _ in0..N { let rt = rt.clone(); let tx = tx.clone();
ths.push(std::thread::spawn(move || {
rt.block_on(async {
tx.send(()).unwrap();
futures::future::pending::<()>().await;
});
}));
}
for _ in0..N {
rx.recv().unwrap();
}
rt.spawn(async {
panic!("boom");
});
for th in ths {
assert!(th.join().is_err());
}
}
#[test] fn rng_seed() { let seed = b"bytes used to generate seed"; let rt1 = tokio::runtime::Builder::new_current_thread()
.rng_seed(RngSeed::from_bytes(seed))
.build()
.unwrap(); let rt1_values = rt1.block_on(async { let rand_1 = tokio::macros::support::thread_rng_n(100); let rand_2 = tokio::macros::support::thread_rng_n(100);
(rand_1, rand_2)
});
let rt2 = tokio::runtime::Builder::new_current_thread()
.rng_seed(RngSeed::from_bytes(seed))
.build()
.unwrap(); let rt2_values = rt2.block_on(async { let rand_1 = tokio::macros::support::thread_rng_n(100); let rand_2 = tokio::macros::support::thread_rng_n(100);
(rand_1, rand_2)
});
assert_eq!(rt1_values, rt2_values);
}
#[test] fn rng_seed_multi_enter() { let seed = b"bytes used to generate seed";
fn two_rand_values() -> (u32, u32) { let rand_1 = tokio::macros::support::thread_rng_n(100); let rand_2 = tokio::macros::support::thread_rng_n(100);
(rand_1, rand_2)
}
let rt1 = tokio::runtime::Builder::new_current_thread()
.rng_seed(RngSeed::from_bytes(seed))
.build()
.unwrap(); let rt1_values_1 = rt1.block_on(async { two_rand_values() }); let rt1_values_2 = rt1.block_on(async { two_rand_values() });
let rt2 = tokio::runtime::Builder::new_current_thread()
.rng_seed(RngSeed::from_bytes(seed))
.build()
.unwrap(); let rt2_values_1 = rt2.block_on(async { two_rand_values() }); let rt2_values_2 = rt2.block_on(async { two_rand_values() });
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.