use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use std::time::Duration;
use tracing::Instrument;
use tracing_calltree::CallTree;
use tracing_subscriber::prelude::*;
#[tokio::test(flavor = "current_thread")]
async fn async_suspension_records_wall_greater_than_active() {
let calltree = CallTree::builder().build();
let subscriber = tracing_subscriber::registry().with(calltree.layer());
let guard = tracing::subscriber::set_default(subscriber);
async {
tokio::task::yield_now().await;
tokio::time::sleep(Duration::from_millis(10)).await;
}
.instrument(tracing::info_span!("database_query"))
.await;
drop(guard);
let snapshot = calltree.snapshot();
let node = &snapshot.roots[0];
assert_eq!(node.total_calls, 1);
assert!(node.wall.mean > node.active.mean);
assert!(node.suspended.mean > Duration::ZERO);
}
#[tokio::test(flavor = "current_thread")]
async fn multiple_polls_produce_one_sample() {
let calltree = CallTree::builder().build();
let subscriber = tracing_subscriber::registry().with(calltree.layer());
let guard = tracing::subscriber::set_default(subscriber);
PollTwice { polls: 0 }
.instrument(tracing::info_span!("poll_twice"))
.await;
drop(guard);
let snapshot = calltree.snapshot();
let node = &snapshot.roots[0];
assert_eq!(node.total_calls, 1);
assert_eq!(node.wall.samples, 1);
}
#[test]
fn nested_reentry_does_not_double_count_active_time() {
let calltree = CallTree::builder().build();
let subscriber = tracing_subscriber::registry().with(calltree.layer());
tracing::subscriber::with_default(subscriber, || {
let span = tracing::info_span!("reentrant");
let outer = span.enter();
std::thread::sleep(Duration::from_millis(2));
{
let inner = span.enter();
std::thread::sleep(Duration::from_millis(2));
drop(inner);
}
std::thread::sleep(Duration::from_millis(2));
drop(outer);
});
let snapshot = calltree.snapshot();
let node = &snapshot.roots[0];
assert_eq!(node.wall.samples, 1);
assert!(node.active.mean <= node.wall.mean);
}
struct PollTwice {
polls: usize,
}
impl Future for PollTwice {
type Output = ();
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
if self.polls == 0 {
self.polls += 1;
cx.waker().wake_by_ref();
Poll::Pending
} else {
Poll::Ready(())
}
}
}