Source code
Revision control
Copy as Markdown
Other Tools
//! Tests for task instrumentation.
//!
//! These tests ensure that the instrumentation for task spawning and task
//! lifecycles is correct.
#![warn(rust_2018_idioms)]
#![cfg(all(tokio_unstable, feature = "tracing", target_has_atomic = "64"))]
use std::{mem, time::Duration};
use tokio::task;
use tracing_mock::{expect, span::NewSpan, subscriber};
#[tokio::test]
async fn task_spawn_creates_span() {
let task_span = expect::span()
.named("runtime.spawn")
.with_target("tokio::task");
let (subscriber, handle) = subscriber::mock()
.new_span(&task_span)
.enter(&task_span)
.exit(&task_span)
// The task span is entered once more when it gets dropped
.enter(&task_span)
.exit(&task_span)
.drop_span(task_span)
.run_with_handle();
{
let _guard = tracing::subscriber::set_default(subscriber);
tokio::spawn(futures::future::ready(()))
.await
.expect("failed to await join handle");
}
handle.assert_finished();
}
#[tokio::test]
async fn task_spawn_loc_file_recorded() {
let task_span = expect::span()
.named("runtime.spawn")
.with_target("tokio::task")
.with_fields(expect::field("loc.file").with_value(&file!()));
let (subscriber, handle) = subscriber::mock().new_span(task_span).run_with_handle();
{
let _guard = tracing::subscriber::set_default(subscriber);
tokio::spawn(futures::future::ready(()))
.await
.expect("failed to await join handle");
}
handle.assert_finished();
}
#[tokio::test]
async fn task_builder_name_recorded() {
let task_span = expect_task_named("test-task");
let (subscriber, handle) = subscriber::mock().new_span(task_span).run_with_handle();
{
let _guard = tracing::subscriber::set_default(subscriber);
task::Builder::new()
.name("test-task")
.spawn(futures::future::ready(()))
.unwrap()
.await
.expect("failed to await join handle");
}
handle.assert_finished();
}
#[tokio::test]
async fn task_builder_loc_file_recorded() {
let task_span = expect::span()
.named("runtime.spawn")
.with_target("tokio::task")
.with_fields(expect::field("loc.file").with_value(&file!()));
let (subscriber, handle) = subscriber::mock().new_span(task_span).run_with_handle();
{
let _guard = tracing::subscriber::set_default(subscriber);
task::Builder::new()
.spawn(futures::future::ready(()))
.unwrap()
.await
.expect("failed to await join handle");
}
handle.assert_finished();
}
#[tokio::test]
async fn task_spawn_sizes_recorded() {
let future = futures::future::ready(());
let size = mem::size_of_val(&future) as u64;
let task_span = expect::span()
.named("runtime.spawn")
.with_target("tokio::task")
// TODO(hds): check that original_size.bytes is NOT recorded when this can be done in
// tracing-mock without listing every other field.
.with_fields(expect::field("size.bytes").with_value(&size));
let (subscriber, handle) = subscriber::mock().new_span(task_span).run_with_handle();
{
let _guard = tracing::subscriber::set_default(subscriber);
task::Builder::new()
.spawn(future)
.unwrap()
.await
.expect("failed to await join handle");
}
handle.assert_finished();
}
#[tokio::test]
async fn task_big_spawn_sizes_recorded() {
let future = {
async fn big<const N: usize>() {
let mut a = [0_u8; N];
for (idx, item) in a.iter_mut().enumerate() {
*item = (idx % 256) as u8;
}
tokio::time::sleep(Duration::from_millis(10)).await;
for (idx, item) in a.iter_mut().enumerate() {
assert_eq!(*item, (idx % 256) as u8);
}
}
// This is larger than the release auto-boxing threshold
big::<20_000>()
};
fn boxed_size<T>(_: &T) -> usize {
mem::size_of::<Box<T>>()
}
let size = mem::size_of_val(&future) as u64;
let boxed_size = boxed_size(&future);
let task_span = expect::span()
.named("runtime.spawn")
.with_target("tokio::task")
.with_fields(
expect::field("size.bytes")
.with_value(&boxed_size)
.and(expect::field("original_size.bytes").with_value(&size)),
);
let (subscriber, handle) = subscriber::mock().new_span(task_span).run_with_handle();
{
let _guard = tracing::subscriber::set_default(subscriber);
task::Builder::new()
.spawn(future)
.unwrap()
.await
.expect("failed to await join handle");
}
handle.assert_finished();
}
/// Expect a task with name
///
/// This is a convenience function to create the expectation for a new task
/// with the `task.name` field set to the provided name.
fn expect_task_named(name: &str) -> NewSpan {
expect::span()
.named("runtime.spawn")
.with_target("tokio::task")
.with_fields(
expect::field("task.name").with_value(&tracing::field::debug(format_args!("{}", name))),
)
}