//! 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() { 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) -> usize { mem::size_of::>() } 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))), ) }