diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /third_party/rust/tracing-attributes/tests/async_fn.rs | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/tracing-attributes/tests/async_fn.rs')
-rw-r--r-- | third_party/rust/tracing-attributes/tests/async_fn.rs | 488 |
1 files changed, 488 insertions, 0 deletions
diff --git a/third_party/rust/tracing-attributes/tests/async_fn.rs b/third_party/rust/tracing-attributes/tests/async_fn.rs new file mode 100644 index 0000000000..d6d874ffd7 --- /dev/null +++ b/third_party/rust/tracing-attributes/tests/async_fn.rs @@ -0,0 +1,488 @@ +use tracing_mock::*; + +use std::convert::Infallible; +use std::{future::Future, pin::Pin, sync::Arc}; +use tracing::subscriber::with_default; +use tracing_attributes::instrument; + +#[instrument] +async fn test_async_fn(polls: usize) -> Result<(), ()> { + let future = PollN::new_ok(polls); + tracing::trace!(awaiting = true); + future.await +} + +// Reproduces a compile error when returning an `impl Trait` from an +// instrumented async fn (see https://github.com/tokio-rs/tracing/issues/1615) +#[allow(dead_code)] // this is just here to test whether it compiles. +#[instrument] +async fn test_ret_impl_trait(n: i32) -> Result<impl Iterator<Item = i32>, ()> { + let n = n; + Ok((0..10).filter(move |x| *x < n)) +} + +// Reproduces a compile error when returning an `impl Trait` from an +// instrumented async fn (see https://github.com/tokio-rs/tracing/issues/1615) +#[allow(dead_code)] // this is just here to test whether it compiles. +#[instrument(err)] +async fn test_ret_impl_trait_err(n: i32) -> Result<impl Iterator<Item = i32>, &'static str> { + Ok((0..10).filter(move |x| *x < n)) +} + +#[instrument] +async fn test_async_fn_empty() {} + +// Reproduces a compile error when an instrumented function body contains inner +// attributes (https://github.com/tokio-rs/tracing/issues/2294). +#[deny(unused_variables)] +#[instrument] +async fn repro_async_2294() { + #![allow(unused_variables)] + let i = 42; +} + +// Reproduces https://github.com/tokio-rs/tracing/issues/1613 +#[instrument] +// LOAD-BEARING `#[rustfmt::skip]`! This is necessary to reproduce the bug; +// with the rustfmt-generated formatting, the lint will not be triggered! +#[rustfmt::skip] +#[deny(clippy::suspicious_else_formatting)] +async fn repro_1613(var: bool) { + println!( + "{}", + if var { "true" } else { "false" } + ); +} + +// Reproduces https://github.com/tokio-rs/tracing/issues/1613 +// and https://github.com/rust-lang/rust-clippy/issues/7760 +#[instrument] +#[deny(clippy::suspicious_else_formatting)] +async fn repro_1613_2() { + // hello world + // else +} + +// Reproduces https://github.com/tokio-rs/tracing/issues/1831 +#[allow(dead_code)] // this is just here to test whether it compiles. +#[instrument] +#[deny(unused_braces)] +fn repro_1831() -> Pin<Box<dyn Future<Output = ()>>> { + Box::pin(async move {}) +} + +// This replicates the pattern used to implement async trait methods on nightly using the +// `type_alias_impl_trait` feature +#[allow(dead_code)] // this is just here to test whether it compiles. +#[instrument(ret, err)] +#[deny(unused_braces)] +#[allow(clippy::manual_async_fn)] +fn repro_1831_2() -> impl Future<Output = Result<(), Infallible>> { + async { Ok(()) } +} + +#[test] +fn async_fn_only_enters_for_polls() { + let (subscriber, handle) = subscriber::mock() + .new_span(span::mock().named("test_async_fn")) + .enter(span::mock().named("test_async_fn")) + .event(event::mock().with_fields(field::mock("awaiting").with_value(&true))) + .exit(span::mock().named("test_async_fn")) + .enter(span::mock().named("test_async_fn")) + .exit(span::mock().named("test_async_fn")) + .enter(span::mock().named("test_async_fn")) + .exit(span::mock().named("test_async_fn")) + .drop_span(span::mock().named("test_async_fn")) + .done() + .run_with_handle(); + with_default(subscriber, || { + block_on_future(async { test_async_fn(2).await }).unwrap(); + }); + handle.assert_finished(); +} + +#[test] +fn async_fn_nested() { + #[instrument] + async fn test_async_fns_nested() { + test_async_fns_nested_other().await + } + + #[instrument] + async fn test_async_fns_nested_other() { + tracing::trace!(nested = true); + } + + let span = span::mock().named("test_async_fns_nested"); + let span2 = span::mock().named("test_async_fns_nested_other"); + let (subscriber, handle) = subscriber::mock() + .new_span(span.clone()) + .enter(span.clone()) + .new_span(span2.clone()) + .enter(span2.clone()) + .event(event::mock().with_fields(field::mock("nested").with_value(&true))) + .exit(span2.clone()) + .enter(span2.clone()) + .exit(span2.clone()) + .drop_span(span2) + .exit(span.clone()) + .enter(span.clone()) + .exit(span.clone()) + .drop_span(span) + .done() + .run_with_handle(); + + with_default(subscriber, || { + block_on_future(async { test_async_fns_nested().await }); + }); + + handle.assert_finished(); +} + +#[test] +fn async_fn_with_async_trait() { + use async_trait::async_trait; + + // test the correctness of the metadata obtained by #[instrument] + // (function name, functions parameters) when async-trait is used + #[async_trait] + pub trait TestA { + async fn foo(&mut self, v: usize); + } + + // test nesting of async fns with aync-trait + #[async_trait] + pub trait TestB { + async fn bar(&self); + } + + // test skip(self) with async-await + #[async_trait] + pub trait TestC { + async fn baz(&self); + } + + #[derive(Debug)] + struct TestImpl(usize); + + #[async_trait] + impl TestA for TestImpl { + #[instrument] + async fn foo(&mut self, v: usize) { + self.baz().await; + self.0 = v; + self.bar().await + } + } + + #[async_trait] + impl TestB for TestImpl { + #[instrument] + async fn bar(&self) { + tracing::trace!(val = self.0); + } + } + + #[async_trait] + impl TestC for TestImpl { + #[instrument(skip(self))] + async fn baz(&self) { + tracing::trace!(val = self.0); + } + } + + let span = span::mock().named("foo"); + let span2 = span::mock().named("bar"); + let span3 = span::mock().named("baz"); + let (subscriber, handle) = subscriber::mock() + .new_span( + span.clone() + .with_field(field::mock("self")) + .with_field(field::mock("v")), + ) + .enter(span.clone()) + .new_span(span3.clone()) + .enter(span3.clone()) + .event(event::mock().with_fields(field::mock("val").with_value(&2u64))) + .exit(span3.clone()) + .enter(span3.clone()) + .exit(span3.clone()) + .drop_span(span3) + .new_span(span2.clone().with_field(field::mock("self"))) + .enter(span2.clone()) + .event(event::mock().with_fields(field::mock("val").with_value(&5u64))) + .exit(span2.clone()) + .enter(span2.clone()) + .exit(span2.clone()) + .drop_span(span2) + .exit(span.clone()) + .enter(span.clone()) + .exit(span.clone()) + .drop_span(span) + .done() + .run_with_handle(); + + with_default(subscriber, || { + let mut test = TestImpl(2); + block_on_future(async { test.foo(5).await }); + }); + + handle.assert_finished(); +} + +#[test] +fn async_fn_with_async_trait_and_fields_expressions() { + use async_trait::async_trait; + + #[async_trait] + pub trait Test { + async fn call(&mut self, v: usize); + } + + #[derive(Clone, Debug)] + struct TestImpl; + + impl TestImpl { + fn foo(&self) -> usize { + 42 + } + } + + #[async_trait] + impl Test for TestImpl { + // check that self is correctly handled, even when using async_trait + #[instrument(fields(val=self.foo(), val2=Self::clone(self).foo(), test=%_v+5))] + async fn call(&mut self, _v: usize) {} + } + + let span = span::mock().named("call"); + let (subscriber, handle) = subscriber::mock() + .new_span( + span.clone().with_field( + field::mock("_v") + .with_value(&5usize) + .and(field::mock("test").with_value(&tracing::field::debug(10))) + .and(field::mock("val").with_value(&42u64)) + .and(field::mock("val2").with_value(&42u64)), + ), + ) + .enter(span.clone()) + .exit(span.clone()) + .enter(span.clone()) + .exit(span.clone()) + .drop_span(span) + .done() + .run_with_handle(); + + with_default(subscriber, || { + block_on_future(async { TestImpl.call(5).await }); + }); + + handle.assert_finished(); +} + +#[test] +fn async_fn_with_async_trait_and_fields_expressions_with_generic_parameter() { + use async_trait::async_trait; + + #[async_trait] + pub trait Test { + async fn call(); + async fn call_with_self(&self); + async fn call_with_mut_self(&mut self); + } + + #[derive(Clone, Debug)] + struct TestImpl; + + // we also test sync functions that return futures, as they should be handled just like + // async-trait (>= 0.1.44) functions + impl TestImpl { + #[instrument(fields(Self=std::any::type_name::<Self>()))] + fn sync_fun(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> { + let val = self.clone(); + Box::pin(async move { + let _ = val; + }) + } + } + + #[async_trait] + impl Test for TestImpl { + // instrumenting this is currently not possible, see https://github.com/tokio-rs/tracing/issues/864#issuecomment-667508801 + //#[instrument(fields(Self=std::any::type_name::<Self>()))] + async fn call() {} + + #[instrument(fields(Self=std::any::type_name::<Self>()))] + async fn call_with_self(&self) { + self.sync_fun().await; + } + + #[instrument(fields(Self=std::any::type_name::<Self>()))] + async fn call_with_mut_self(&mut self) {} + } + + //let span = span::mock().named("call"); + let span2 = span::mock().named("call_with_self"); + let span3 = span::mock().named("call_with_mut_self"); + let span4 = span::mock().named("sync_fun"); + let (subscriber, handle) = subscriber::mock() + /*.new_span(span.clone() + .with_field( + field::mock("Self").with_value(&"TestImpler"))) + .enter(span.clone()) + .exit(span.clone()) + .drop_span(span)*/ + .new_span( + span2 + .clone() + .with_field(field::mock("Self").with_value(&std::any::type_name::<TestImpl>())), + ) + .enter(span2.clone()) + .new_span( + span4 + .clone() + .with_field(field::mock("Self").with_value(&std::any::type_name::<TestImpl>())), + ) + .enter(span4.clone()) + .exit(span4.clone()) + .enter(span4.clone()) + .exit(span4) + .exit(span2.clone()) + .enter(span2.clone()) + .exit(span2.clone()) + .drop_span(span2) + .new_span( + span3 + .clone() + .with_field(field::mock("Self").with_value(&std::any::type_name::<TestImpl>())), + ) + .enter(span3.clone()) + .exit(span3.clone()) + .enter(span3.clone()) + .exit(span3.clone()) + .drop_span(span3) + .done() + .run_with_handle(); + + with_default(subscriber, || { + block_on_future(async { + TestImpl::call().await; + TestImpl.call_with_self().await; + TestImpl.call_with_mut_self().await + }); + }); + + handle.assert_finished(); +} + +#[test] +fn out_of_scope_fields() { + // Reproduces tokio-rs/tracing#1296 + + struct Thing { + metrics: Arc<()>, + } + + impl Thing { + #[instrument(skip(self, _req), fields(app_id))] + fn call(&mut self, _req: ()) -> Pin<Box<dyn Future<Output = Arc<()>> + Send + Sync>> { + // ... + let metrics = self.metrics.clone(); + // ... + Box::pin(async move { + // ... + metrics // cannot find value `metrics` in this scope + }) + } + } + + let span = span::mock().named("call"); + let (subscriber, handle) = subscriber::mock() + .new_span(span.clone()) + .enter(span.clone()) + .exit(span.clone()) + .enter(span.clone()) + .exit(span.clone()) + .drop_span(span) + .done() + .run_with_handle(); + + with_default(subscriber, || { + block_on_future(async { + let mut my_thing = Thing { + metrics: Arc::new(()), + }; + my_thing.call(()).await; + }); + }); + + handle.assert_finished(); +} + +#[test] +fn manual_impl_future() { + #[allow(clippy::manual_async_fn)] + #[instrument] + fn manual_impl_future() -> impl Future<Output = ()> { + async { + tracing::trace!(poll = true); + } + } + + let span = span::mock().named("manual_impl_future"); + let poll_event = || event::mock().with_fields(field::mock("poll").with_value(&true)); + + let (subscriber, handle) = subscriber::mock() + // await manual_impl_future + .new_span(span.clone()) + .enter(span.clone()) + .event(poll_event()) + .exit(span.clone()) + .enter(span.clone()) + .exit(span.clone()) + .drop_span(span) + .done() + .run_with_handle(); + + with_default(subscriber, || { + block_on_future(async { + manual_impl_future().await; + }); + }); + + handle.assert_finished(); +} + +#[test] +fn manual_box_pin() { + #[instrument] + fn manual_box_pin() -> Pin<Box<dyn Future<Output = ()>>> { + Box::pin(async { + tracing::trace!(poll = true); + }) + } + + let span = span::mock().named("manual_box_pin"); + let poll_event = || event::mock().with_fields(field::mock("poll").with_value(&true)); + + let (subscriber, handle) = subscriber::mock() + // await manual_box_pin + .new_span(span.clone()) + .enter(span.clone()) + .event(poll_event()) + .exit(span.clone()) + .enter(span.clone()) + .exit(span.clone()) + .drop_span(span) + .done() + .run_with_handle(); + + with_default(subscriber, || { + block_on_future(async { + manual_box_pin().await; + }); + }); + + handle.assert_finished(); +} |