From 8c8098160ecc0a1b974ef5a12c3d34bb091d7060 Mon Sep 17 00:00:00 2001 From: Hayden Stainsby Date: Thu, 3 Oct 2024 15:18:50 +0200 Subject: [PATCH 1/3] mock: improve ergonomics when an `ExpectedSpan` is needed Many of the methods on `MockCollector` take an `ExpectedSpan`. This often requires significant boilerplate. For example, to expect that a span with a specific name enters and then exits, the following code is needed: ```rust let span = expect::span().named("span name"); let (collector, handle) = collector::mock() .enter(span.clone()) .exit(span) .run_with_handle(); ``` In order to make using `tracing-mock` more ergonomic and also more compact, the `MockCollector` and `MockSubscriber` methods that previous took an `ExpectedSpan`, are now generic over `Into`. There are currently 3 implementations of `From` for `ExpectedSpan` which allow the following shorthand uses: `T: Into` - an `ExpectedSpan` will be created that expects to have a name specified by `T`. ```rust let (collector, handle) = collector::mock() .enter("span name") .exit("span name") .run_with_handle(); ``` `&ExpectedId` - an `ExpectedSpan` will be created that expects to have the expected Id. A reference is taken and cloned internally because the caller always needs to use an `ExpectedId` in at least 2 calls to the mock collector/subscriber. ```rust let id = expect::id(); let (collector, handle) = collector::mock() .new_span(&id) .enter(&id) .run_with_handle(); ``` `&ExpectedSpan` - The expected span is taken by reference and cloned. ```rust let span = expect::span().named("span name"); let (collector, handle) = collector::mock() .enter(&span) .exit(&span) .run_with_handle(); ``` In Rust, taking a reference to an object and immediately cloning it is an anti-pattern. It is considered better to force the user to clone outside the API to make the cloning explict. However, in the case of a testing framework, it seems reasonable to prefer a more concise API, rather than having it more explicit. To reduce the size of this PR and to avoid unnecessary churn in other crates, the tests within the tracing repo which use `tracing-mock` will not be updated to use the new `Into` capabilities. The new API is backwards compatible and those tests can remain as they are. --- tracing-mock/src/collector.rs | 74 ++++++++++------- tracing-mock/src/span.rs | 142 +++++++++++++++++++++++++++------ tracing-mock/src/subscriber.rs | 42 +++++----- 3 files changed, 190 insertions(+), 68 deletions(-) diff --git a/tracing-mock/src/collector.rs b/tracing-mock/src/collector.rs index 89f74d05de..4789b7ce64 100644 --- a/tracing-mock/src/collector.rs +++ b/tracing-mock/src/collector.rs @@ -38,11 +38,11 @@ //! .named("my_span"); //! let (collector, handle) = collector::mock() //! // Enter a matching span -//! .enter(span.clone()) +//! .enter(&span) //! // Record an event with message "collect parting message" //! .event(expect::event().with_fields(expect::message("collect parting message"))) //! // Record a value for the field `parting` on a matching span -//! .record(span.clone(), expect::field("parting").with_value(&"goodbye world!")) +//! .record(&span, expect::field("parting").with_value(&"goodbye world!")) //! // Exit a matching span //! .exit(span) //! // Expect no further messages to be recorded @@ -80,9 +80,9 @@ //! let span = expect::span() //! .named("my_span"); //! let (collector, handle) = collector::mock() -//! .enter(span.clone()) +//! .enter(&span) //! .event(expect::event().with_fields(expect::message("collect parting message"))) -//! .record(span.clone(), expect::field("parting").with_value(&"goodbye world!")) +//! .record(&span, expect::field("parting").with_value(&"goodbye world!")) //! .exit(span) //! .only() //! .run_with_handle(); @@ -225,11 +225,11 @@ pub struct MockHandle(Arc>>, String); /// .named("my_span"); /// let (collector, handle) = collector::mock() /// // Enter a matching span -/// .enter(span.clone()) +/// .enter(&span) /// // Record an event with message "collect parting message" /// .event(expect::event().with_fields(expect::message("collect parting message"))) /// // Record a value for the field `parting` on a matching span -/// .record(span.clone(), expect::field("parting").with_value(&"goodbye world!")) +/// .record(&span, expect::field("parting").with_value(&"goodbye world!")) /// // Exit a matching span /// .exit(span) /// // Expect no further messages to be recorded @@ -472,8 +472,8 @@ where /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (collector, handle) = collector::mock() - /// .enter(span.clone()) - /// .exit(span) + /// .enter(&span) + /// .exit(&span) /// .only() /// .run_with_handle(); /// @@ -495,8 +495,8 @@ where /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (collector, handle) = collector::mock() - /// .enter(span.clone()) - /// .exit(span) + /// .enter(&span) + /// .exit(&span) /// .only() /// .run_with_handle(); /// @@ -511,8 +511,11 @@ where /// /// [`exit`]: fn@Self::exit /// [`only`]: fn@Self::only - pub fn enter(mut self, span: ExpectedSpan) -> Self { - self.expected.push_back(Expect::Enter(span)); + pub fn enter(mut self, span: S) -> Self + where + S: Into, + { + self.expected.push_back(Expect::Enter(span.into())); self } @@ -536,8 +539,8 @@ where /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (collector, handle) = collector::mock() - /// .enter(span.clone()) - /// .exit(span) + /// .enter(&span) + /// .exit(&span) /// .run_with_handle(); /// /// tracing::collect::with_default(collector, || { @@ -558,8 +561,8 @@ where /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (collector, handle) = collector::mock() - /// .enter(span.clone()) - /// .exit(span) + /// .enter(&span) + /// .exit(&span) /// .run_with_handle(); /// /// tracing::collect::with_default(collector, || { @@ -572,8 +575,11 @@ where /// ``` /// /// [`enter`]: fn@Self::enter - pub fn exit(mut self, span: ExpectedSpan) -> Self { - self.expected.push_back(Expect::Exit(span)); + pub fn exit(mut self, span: S) -> Self + where + S: Into, + { + self.expected.push_back(Expect::Exit(span.into())); self } @@ -627,8 +633,11 @@ where /// /// handle.assert_finished(); /// ``` - pub fn clone_span(mut self, span: ExpectedSpan) -> Self { - self.expected.push_back(Expect::CloneSpan(span)); + pub fn clone_span(mut self, span: S) -> Self + where + S: Into, + { + self.expected.push_back(Expect::CloneSpan(span.into())); self } @@ -644,8 +653,11 @@ where /// /// [`Collect::drop_span`]: fn@tracing::Collect::drop_span #[allow(deprecated)] - pub fn drop_span(mut self, span: ExpectedSpan) -> Self { - self.expected.push_back(Expect::DropSpan(span)); + pub fn drop_span(mut self, span: S) -> Self + where + S: Into, + { + self.expected.push_back(Expect::DropSpan(span.into())); self } @@ -710,9 +722,15 @@ where /// ``` /// /// [`Span::follows_from`]: fn@tracing::Span::follows_from - pub fn follows_from(mut self, consequence: ExpectedSpan, cause: ExpectedSpan) -> Self { - self.expected - .push_back(Expect::FollowsFrom { consequence, cause }); + pub fn follows_from(mut self, consequence: S1, cause: S2) -> Self + where + S1: Into, + S2: Into, + { + self.expected.push_back(Expect::FollowsFrom { + consequence: consequence.into(), + cause: cause.into(), + }); self } @@ -775,11 +793,13 @@ where /// ``` /// /// [`field`]: mod@crate::field - pub fn record(mut self, span: ExpectedSpan, fields: I) -> Self + pub fn record(mut self, span: S, fields: I) -> Self where + S: Into, I: Into, { - self.expected.push_back(Expect::Visit(span, fields.into())); + self.expected + .push_back(Expect::Visit(span.into(), fields.into())); self } diff --git a/tracing-mock/src/span.rs b/tracing-mock/src/span.rs index a568484f76..34568551b3 100644 --- a/tracing-mock/src/span.rs +++ b/tracing-mock/src/span.rs @@ -18,8 +18,8 @@ //! .at_level(tracing::Level::INFO); //! //! let (collector, handle) = collector::mock() -//! .enter(span.clone()) -//! .exit(span) +//! .enter(&span) +//! .exit(&span) //! .run_with_handle(); //! //! tracing::collect::with_default(collector, || { @@ -30,6 +30,25 @@ //! handle.assert_finished(); //! ``` //! +//! Instead of passing an `ExpectedSpan`, the collector methods will also accept +//! anything that implements `Into` which is shorthand for +//! `expect::span().named(name)`. +//! +//! ``` +//! use tracing_mock::collector; +//! +//! let (collector, handle) = collector::mock() +//! .enter("interesting_span") +//! .run_with_handle(); +//! +//! tracing::collect::with_default(collector, || { +//! let span = tracing::info_span!("interesting_span"); +//! let _guard = span.enter(); +//! }); +//! +//! handle.assert_finished(); +//! ``` +// //! The following example asserts the name, level, parent, and fields of the span: //! //! ``` @@ -44,10 +63,10 @@ //! .with_ancestry(expect::has_explicit_parent("parent_span")); //! //! let (collector, handle) = collector::mock() -//! .new_span(expect::span().named("parent_span")) +//! .new_span("parent_span") //! .new_span(new_span) -//! .enter(span.clone()) -//! .exit(span) +//! .enter(&span) +//! .exit(&span) //! .run_with_handle(); //! //! tracing::collect::with_default(collector, || { @@ -75,8 +94,8 @@ //! .at_level(tracing::Level::INFO); //! //! let (collector, handle) = collector::mock() -//! .enter(span.clone()) -//! .exit(span) +//! .enter(&span) +//! .exit(&span) //! .run_with_handle(); //! //! tracing::collect::with_default(collector, || { @@ -115,6 +134,27 @@ pub struct ExpectedSpan { pub(crate) metadata: ExpectedMetadata, } +impl From for ExpectedSpan +where + I: Into, +{ + fn from(name: I) -> Self { + ExpectedSpan::default().named(name) + } +} + +impl From<&ExpectedId> for ExpectedSpan { + fn from(id: &ExpectedId) -> Self { + ExpectedSpan::default().with_id(id.clone()) + } +} + +impl From<&ExpectedSpan> for ExpectedSpan { + fn from(span: &ExpectedSpan) -> Self { + span.clone() + } +} + /// A mock new span. /// /// **Note**: This struct contains expectations that can only be asserted @@ -166,7 +206,8 @@ pub struct ExpectedId { impl ExpectedSpan { /// Sets a name to expect when matching a span. /// - /// If an event is recorded with a name that differs from the one provided to this method, the expectation will fail. + /// If an event is recorded with a name that differs from the one provided to this method, the + /// expectation will fail. /// /// # Examples /// @@ -187,6 +228,25 @@ impl ExpectedSpan { /// handle.assert_finished(); /// ``` /// + /// If only the name of the span needs to be validated, then + /// instead of using the `named` method, a string can be passed + /// to the [`MockCollector`] functions directly. + /// + /// ``` + /// use tracing_mock::collector; + /// + /// let (collector, handle) = collector::mock() + /// .enter("span name") + /// .run_with_handle(); + /// + /// tracing::collect::with_default(collector, || { + /// let span = tracing::info_span!("span name"); + /// let _guard = span.enter(); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// /// When the span name is different, the assertion will fail: /// /// ```should_panic @@ -205,6 +265,8 @@ impl ExpectedSpan { /// /// handle.assert_finished(); /// ``` + /// + /// [`MockCollector`]: struct@crate::collector::MockCollector pub fn named(self, name: I) -> Self where I: Into, @@ -247,10 +309,41 @@ impl ExpectedSpan { /// let span2 = expect::span().named("span").with_id(id2.clone()); /// /// let (collector, handle) = collector::mock() - /// .new_span(span1.clone()) - /// .new_span(span2.clone()) - /// .enter(span2) - /// .enter(span1) + /// .new_span(&span1) + /// .new_span(&span2) + /// .enter(&span2) + /// .enter(&span1) + /// .run_with_handle(); + /// + /// tracing::collect::with_default(collector, || { + /// fn create_span() -> tracing::Span { + /// tracing::info_span!("span") + /// } + /// + /// let span1 = create_span(); + /// let span2 = create_span(); + /// + /// let _guard2 = span2.enter(); + /// let _guard1 = span1.enter(); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// Since `ExpectedId` implements `Into`, in cases where + /// only checking on Id is desired, a shorthand version of the previous + /// example can be used. + /// + /// ``` + /// use tracing_mock::{collector, expect}; + /// let id1 = expect::id(); + /// let id2 = expect::id(); + /// + /// let (collector, handle) = collector::mock() + /// .new_span(&id1) + /// .new_span(&id2) + /// .enter(&id2) + /// .enter(&id1) /// .run_with_handle(); /// /// tracing::collect::with_default(collector, || { @@ -279,10 +372,10 @@ impl ExpectedSpan { /// let span2 = expect::span().named("span").with_id(id2.clone()); /// /// let (collector, handle) = collector::mock() - /// .new_span(span1.clone()) - /// .new_span(span2.clone()) - /// .enter(span2) - /// .enter(span1) + /// .new_span(&span1) + /// .new_span(&span2) + /// .enter(&span2) + /// .enter(&span1) /// .run_with_handle(); /// /// tracing::collect::with_default(collector, || { @@ -496,8 +589,8 @@ impl ExpectedSpan { /// .with_ancestry(expect::has_contextual_parent("parent_span")); /// /// let (collector, handle) = collector::mock() - /// .new_span(parent_span.clone()) - /// .enter(parent_span) + /// .new_span(&parent_span) + /// .enter(&parent_span) /// .new_span(span) /// .run_with_handle(); /// @@ -542,8 +635,8 @@ impl ExpectedSpan { /// .with_ancestry(expect::has_explicit_parent("parent_span")); /// /// let (collector, handle) = collector::mock() - /// .new_span(parent_span.clone()) - /// .enter(parent_span) + /// .new_span(&parent_span) + /// .enter(&parent_span) /// .new_span(span) /// .run_with_handle(); /// @@ -695,10 +788,13 @@ impl fmt::Display for ExpectedSpan { } } -impl From for NewSpan { - fn from(span: ExpectedSpan) -> Self { +impl From for NewSpan +where + S: Into, +{ + fn from(span: S) -> Self { Self { - span, + span: span.into(), ..Default::default() } } diff --git a/tracing-mock/src/subscriber.rs b/tracing-mock/src/subscriber.rs index 07d8bb39a0..16ed3a59f8 100644 --- a/tracing-mock/src/subscriber.rs +++ b/tracing-mock/src/subscriber.rs @@ -40,11 +40,11 @@ //! .named("my_span"); //! let (subscriber, handle) = subscriber::mock() //! // Enter a matching span -//! .enter(span.clone()) +//! .enter(&span) //! // Record an event with message "collect parting message" //! .event(expect::event().with_fields(expect::message("say hello"))) //! // Exit a matching span -//! .exit(span) +//! .exit(&span) //! // Expect no further messages to be recorded //! .only() //! // Return the collector and handle @@ -82,11 +82,11 @@ //! .named("my_span"); //! let (subscriber, handle) = subscriber::mock() //! // Enter a matching span -//! .enter(span.clone()) +//! .enter(&span) //! // Record an event with message "collect parting message" //! .event(expect::event().with_fields(expect::message("say hello"))) //! // Exit a matching span -//! .exit(span) +//! .exit(&span) //! // Expect no further messages to be recorded //! .only() //! // Return the collector and handle @@ -153,11 +153,11 @@ use std::{ /// .named("my_span"); /// let (subscriber, handle) = subscriber::mock() /// // Enter a matching span -/// .enter(span.clone()) +/// .enter(&span) /// // Record an event with message "collect parting message" /// .event(expect::event().with_fields(expect::message("say hello"))) /// // Exit a matching span -/// .exit(span) +/// .exit(&span) /// // Expect no further messages to be recorded /// .only() /// // Return the collector and handle @@ -505,8 +505,8 @@ impl MockSubscriberBuilder { /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (subscriber, handle) = subscriber::mock() - /// .enter(span.clone()) - /// .exit(span) + /// .enter(&span) + /// .exit(&span) /// .only() /// .run_with_handle(); /// @@ -533,8 +533,8 @@ impl MockSubscriberBuilder { /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (subscriber, handle) = subscriber::mock() - /// .enter(span.clone()) - /// .exit(span) + /// .enter(&span) + /// .exit(&span) /// .only() /// .run_with_handle(); /// @@ -553,8 +553,11 @@ impl MockSubscriberBuilder { /// /// [`exit`]: fn@Self::exit /// [`only`]: fn@Self::only - pub fn enter(mut self, span: ExpectedSpan) -> Self { - self.expected.push_back(Expect::Enter(span)); + pub fn enter(mut self, span: S) -> Self + where + S: Into, + { + self.expected.push_back(Expect::Enter(span.into())); self } @@ -582,8 +585,8 @@ impl MockSubscriberBuilder { /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (subscriber, handle) = subscriber::mock() - /// .enter(span.clone()) - /// .exit(span) + /// .enter(&span) + /// .exit(&span) /// .only() /// .run_with_handle(); /// @@ -609,8 +612,8 @@ impl MockSubscriberBuilder { /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (subscriber, handle) = subscriber::mock() - /// .enter(span.clone()) - /// .exit(span) + /// .enter(&span) + /// .exit(&span) /// .only() /// .run_with_handle(); /// @@ -630,8 +633,11 @@ impl MockSubscriberBuilder { /// [`enter`]: fn@Self::enter /// [`MockHandle::assert_finished`]: fn@crate::collector::MockHandle::assert_finished /// [`Span::enter`]: fn@tracing::Span::enter - pub fn exit(mut self, span: ExpectedSpan) -> Self { - self.expected.push_back(Expect::Exit(span)); + pub fn exit(mut self, span: S) -> Self + where + S: Into, + { + self.expected.push_back(Expect::Exit(span.into())); self } From 39438f4453e7c86b9de60db037d4c6e396a4335d Mon Sep 17 00:00:00 2001 From: Hayden Stainsby Date: Thu, 3 Oct 2024 14:32:46 +0200 Subject: [PATCH 2/3] mock: match parent span on `ExpectedSpan` The `with_ancestry` methods on `NewSpan` and `ExpectedEvent` provide a way to match whether the span or event is a contextual or explicit root or if it has a contextual or explicit parent span. However, in the case of matching on a contextual or explicit parent span, only the span name could be used for matching. This is sufficiently precise when testing tracing instrumentation in other libraries or applications as opposed to testing tracing itself. It is likely that a user would like to test that some span or event has a specific span as a parent, and not just any span with a specific name, in many cases, all the possible parent spans may have the same name. This is the case when testing tracing instrumentation in Tokio. To solve this problem, the `Ancestry` struct was renamed to `ExpectedAncestry` and in the case of expecting an explicit or conextual parent, an `ExpectedSpan` object can be passed in. This provides the maximum possible flexibility. The convenience functions in the `expect` module now take `Into` so that existing tests that pass a string type object for the parent will see the same behaviour as previously and shorthand use for expected Ids is also available. Additionally, the span checking code has been unified between the `MockCollector` and `MockSubscriber` cases and the assertion descriptions have been improved to make them more readable. --- tracing-mock/src/ancestry.rs | 117 +++++++++++++------- tracing-mock/src/collector.rs | 69 ++++++------ tracing-mock/src/event.rs | 46 ++++++-- tracing-mock/src/expect.rs | 18 +-- tracing-mock/src/metadata.rs | 65 +++++++---- tracing-mock/src/span.rs | 148 ++++++++++++++++++++----- tracing-mock/src/subscriber.rs | 128 ++++++--------------- tracing-mock/tests/event_ancestry.rs | 148 +++++++++++++++++-------- tracing-mock/tests/span_ancestry.rs | 160 +++++++++++++++++++-------- 9 files changed, 577 insertions(+), 322 deletions(-) diff --git a/tracing-mock/src/ancestry.rs b/tracing-mock/src/ancestry.rs index ee661d45e8..2b96c289b3 100644 --- a/tracing-mock/src/ancestry.rs +++ b/tracing-mock/src/ancestry.rs @@ -7,65 +7,96 @@ use tracing_core::{ Event, }; +use crate::span::{ActualSpan, ExpectedSpan}; + /// The ancestry of an event or span. /// /// An event or span can have an explicitly assigned parent, or be an explicit root. Otherwise, /// an event or span may have a contextually assigned parent or in the final case will be a /// contextual root. #[derive(Debug, Eq, PartialEq)] -pub enum Ancestry { - /// The event or span has an explicitly assigned parent (created with `parent: span_id`) with - /// the specified name. - HasExplicitParent(String), +pub enum ExpectedAncestry { + /// The event or span has an explicitly assigned parent (created with `parent: span_id`) span. + HasExplicitParent(ExpectedSpan), /// The event or span is an explicitly defined root. It was created with `parent: None` and /// has no parent. IsExplicitRoot, - /// The event or span has a contextually assigned parent with the specified name. It has no - /// explicitly assigned parent, nor has it been explicitly defined as a root (it was created - /// without the `parent:` directive). There was a span in context when this event or span was - /// created. - HasContextualParent(String), + /// The event or span has a contextually assigned parent span. It has no explicitly assigned + /// parent span, nor has it been explicitly defined as a root (it was created without the + /// `parent:` directive). There was a span in context when this event or span was created. + HasContextualParent(ExpectedSpan), /// The event or span is a contextual root. It has no explicitly assigned parent, nor has it /// been explicitly defined as a root (it was created without the `parent:` directive). /// Additionally, no span was in context when this event or span was created. IsContextualRoot, } -impl Ancestry { +pub(crate) enum ActualAncestry { + HasExplicitParent(ActualSpan), + IsExplicitRoot, + HasContextualParent(ActualSpan), + IsContextualRoot, +} + +impl ExpectedAncestry { #[track_caller] pub(crate) fn check( &self, - actual_ancestry: &Ancestry, + actual_ancestry: &ActualAncestry, ctx: impl std::fmt::Display, collector_name: &str, ) { - let expected_description = |ancestry: &Ancestry| match ancestry { - Self::IsExplicitRoot => "be an explicit root".to_string(), - Self::HasExplicitParent(name) => format!("have an explicit parent with name='{name}'"), - Self::IsContextualRoot => "be a contextual root".to_string(), - Self::HasContextualParent(name) => { - format!("have a contextual parent with name='{name}'") + match (self, actual_ancestry) { + (Self::IsExplicitRoot, ActualAncestry::IsExplicitRoot) => {} + (Self::IsContextualRoot, ActualAncestry::IsContextualRoot) => {} + ( + Self::HasExplicitParent(expected_parent), + ActualAncestry::HasExplicitParent(actual_parent), + ) => { + expected_parent.check( + actual_parent, + format_args!("{ctx} to have an explicit parent span"), + collector_name, + ); } - }; - - let actual_description = |ancestry: &Ancestry| match ancestry { - Self::IsExplicitRoot => "was actually an explicit root".to_string(), - Self::HasExplicitParent(name) => { - format!("actually has an explicit parent with name='{name}'") + ( + Self::HasContextualParent(expected_parent), + ActualAncestry::HasContextualParent(actual_parent), + ) => { + println!("----> [{collector_name}] check {expected_parent:?} against actual parent with Id={id:?}", id = actual_parent.id()); + expected_parent.check( + actual_parent, + format_args!("{ctx} to have a contextual parent span"), + collector_name, + ); } - Self::IsContextualRoot => "was actually a contextual root".to_string(), - Self::HasContextualParent(name) => { - format!("actually has a contextual parent with name='{name}'") + _ => { + // Ancestry types don't match at all. + let expected_description = match self { + Self::IsExplicitRoot => "be an explicit root", + Self::HasExplicitParent(_) => "have an explicit parent span", + Self::IsContextualRoot => "be a contextual root", + Self::HasContextualParent(_) => "have a contextual parent span", + }; + + let actual_description = match actual_ancestry { + ActualAncestry::IsExplicitRoot => "is actually an explicit root", + ActualAncestry::HasExplicitParent(_) => "actually has an explicit parent span", + ActualAncestry::IsContextualRoot => "is actually a contextual root", + ActualAncestry::HasContextualParent(_) => { + "actually has a contextual parent span" + } + }; + + panic!( + "{}", + format!( + "[{collector_name}] expected {ctx} to {expected_description}, \ + but it {actual_description}" + ) + ); } - }; - - assert_eq!( - self, - actual_ancestry, - "[{collector_name}] expected {ctx} to {expected_description}, but {actual_description}", - expected_description = expected_description(self), - actual_description = actual_description(actual_ancestry) - ); + } } } @@ -120,29 +151,29 @@ impl HasAncestry for &Attributes<'_> { pub(crate) fn get_ancestry( item: impl HasAncestry, lookup_current: impl FnOnce() -> Option, - span_name: impl FnOnce(&span::Id) -> Option<&str>, -) -> Ancestry { + actual_span: impl FnOnce(&span::Id) -> Option, +) -> ActualAncestry { if item.is_contextual() { if let Some(parent_id) = lookup_current() { - let contextual_parent_name = span_name(&parent_id).expect( + let contextual_parent_span = actual_span(&parent_id).expect( "tracing-mock: contextual parent cannot \ be looked up by ID. Was it recorded correctly?", ); - Ancestry::HasContextualParent(contextual_parent_name.to_string()) + ActualAncestry::HasContextualParent(contextual_parent_span) } else { - Ancestry::IsContextualRoot + ActualAncestry::IsContextualRoot } } else if item.is_root() { - Ancestry::IsExplicitRoot + ActualAncestry::IsExplicitRoot } else { let parent_id = item.parent().expect( "tracing-mock: is_contextual=false is_root=false \ but no explicit parent found. This is a bug!", ); - let explicit_parent_name = span_name(parent_id).expect( + let explicit_parent_span = actual_span(parent_id).expect( "tracing-mock: explicit parent cannot be looked \ up by ID. Is the provided Span ID valid: {parent_id}", ); - Ancestry::HasExplicitParent(explicit_parent_name.to_string()) + ActualAncestry::HasExplicitParent(explicit_parent_span) } } diff --git a/tracing-mock/src/collector.rs b/tracing-mock/src/collector.rs index 4789b7ce64..9f27e10785 100644 --- a/tracing-mock/src/collector.rs +++ b/tracing-mock/src/collector.rs @@ -142,7 +142,7 @@ use crate::{ event::ExpectedEvent, expect::Expect, field::ExpectedFields, - span::{ExpectedSpan, NewSpan}, + span::{ActualSpan, ExpectedSpan, NewSpan}, }; use std::{ collections::{HashMap, VecDeque}, @@ -160,19 +160,15 @@ use tracing::{ }; pub(crate) struct SpanState { - id: u64, + id: Id, name: &'static str, refs: usize, meta: &'static Metadata<'static>, } -impl SpanState { - pub(crate) fn id(&self) -> u64 { - self.id - } - - pub(crate) fn metadata(&self) -> &'static Metadata<'static> { - self.meta +impl From<&SpanState> for ActualSpan { + fn from(span_state: &SpanState) -> Self { + Self::new(span_state.id.clone(), Some(span_state.meta)) } } @@ -1069,7 +1065,7 @@ where .lock() .unwrap() .get(span_id) - .map(|span| span.name) + .map(|span| span.into()) }, ) }; @@ -1140,7 +1136,7 @@ where get_ancestry( span, || self.lookup_current(), - |span_id| spans.get(span_id).map(|span| span.name), + |span_id| spans.get(span_id).map(|span| span.into()), ) }, &self.name, @@ -1150,7 +1146,7 @@ where spans.insert( id.clone(), SpanState { - id: id.into_u64(), + id: id.clone(), name: meta.name(), refs: 1, meta, @@ -1166,7 +1162,7 @@ where match self.expected.lock().unwrap().pop_front() { None => {} Some(Expect::Enter(ref expected_span)) => { - expected_span.check(span, &self.name); + expected_span.check(&span.into(), "to enter a span", &self.name); } Some(ex) => ex.bad(&self.name, format_args!("entered span {:?}", span.name)), } @@ -1189,7 +1185,7 @@ where match self.expected.lock().unwrap().pop_front() { None => {} Some(Expect::Exit(ref expected_span)) => { - expected_span.check(span, &self.name); + expected_span.check(&span.into(), "to exit a span", &self.name); let curr = self.current.lock().unwrap().pop(); assert_eq!( Some(id), @@ -1205,27 +1201,34 @@ where } fn clone_span(&self, id: &Id) -> Id { - let name = self.spans.lock().unwrap().get_mut(id).map(|span| { - let name = span.name; - println!( - "[{}] clone_span: {}; id={:?}; refs={:?};", - self.name, name, id, span.refs - ); - span.refs += 1; - name - }); - if name.is_none() { - println!("[{}] clone_span: id={:?};", self.name, id); + let mut spans = self.spans.lock().unwrap(); + let mut span = spans.get_mut(id); + match span.as_deref_mut() { + Some(span) => { + println!( + "[{}] clone_span: {}; id={:?}; refs={:?};", + self.name, span.name, id, span.refs, + ); + span.refs += 1; + } + None => { + println!( + "[{}] clone_span: id={:?} (not found in span list);", + self.name, id + ); + } } + let mut expected = self.expected.lock().unwrap(); - let was_expected = if let Some(Expect::CloneSpan(ref span)) = expected.front() { - assert_eq!( - name, - span.name(), - "[{}] expected to clone a span named {:?}", - self.name, - span.name() - ); + let was_expected = if let Some(Expect::CloneSpan(ref expected_span)) = expected.front() { + match span { + Some(actual_span) => { + let actual_span: &_ = actual_span; + expected_span.check(&actual_span.into(), "to clone a span", &self.name); + } + // Check only by Id + None => expected_span.check(&id.into(), "to clone a span", &self.name), + } true } else { false diff --git a/tracing-mock/src/event.rs b/tracing-mock/src/event.rs index 630f005a84..1e52b72320 100644 --- a/tracing-mock/src/event.rs +++ b/tracing-mock/src/event.rs @@ -29,7 +29,12 @@ //! [`collector`]: mod@crate::collector //! [`expect::event`]: fn@crate::expect::event #![allow(missing_docs)] -use crate::{ancestry::Ancestry, expect, field, metadata::ExpectedMetadata, span}; +use crate::{ + ancestry::{ActualAncestry, ExpectedAncestry}, + expect, field, + metadata::ExpectedMetadata, + span, +}; use std::fmt; @@ -42,7 +47,7 @@ use std::fmt; #[derive(Default, Eq, PartialEq)] pub struct ExpectedEvent { pub(super) fields: Option, - pub(super) ancestry: Option, + pub(super) ancestry: Option, pub(super) in_spans: Option>, pub(super) metadata: ExpectedMetadata, } @@ -267,9 +272,34 @@ impl ExpectedEvent { /// /// # Examples /// - /// If `expect::has_explicit_parent("parent_name")` is passed - /// `with_ancestry` then the provided string is the name of the explicit - /// parent span to expect. + /// An explicit or contextual can be matched on an `ExpectedSpan`. + /// + /// ``` + /// use tracing::collect::with_default; + /// use tracing_mock::{collector, expect}; + /// + /// let parent = expect::span() + /// .named("parent_span") + /// .with_target("custom-target") + /// .at_level(tracing::Level::INFO); + /// let event = expect::event() + /// .with_ancestry(expect::has_explicit_parent(parent)); + /// + /// let (collector, handle) = collector::mock() + /// .event(event) + /// .run_with_handle(); + /// + /// with_default(collector, || { + /// let parent = tracing::info_span!(target: "custom-target", "parent_span"); + /// tracing::info!(parent: parent.id(), field = &"value"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// The functions `expect::has_explicit_parent` and + /// `expect::has_contextual_parent` take `Into`, so a string + /// passed directly will match on a span with that name, or an + /// [`ExpectedId`] can be passed to match a span with that Id. /// /// ``` /// use tracing::collect::with_default; @@ -382,7 +412,9 @@ impl ExpectedEvent { /// /// handle.assert_finished(); /// ``` - pub fn with_ancestry(self, ancenstry: Ancestry) -> ExpectedEvent { + /// + /// [`ExpectedId`]: struct@crate::span::ExpectedId + pub fn with_ancestry(self, ancenstry: ExpectedAncestry) -> ExpectedEvent { Self { ancestry: Some(ancenstry), ..self @@ -506,7 +538,7 @@ impl ExpectedEvent { pub(crate) fn check( &mut self, event: &tracing::Event<'_>, - get_ancestry: impl FnOnce() -> Ancestry, + get_ancestry: impl FnOnce() -> ActualAncestry, collector_name: &str, ) { let meta = event.metadata(); diff --git a/tracing-mock/src/expect.rs b/tracing-mock/src/expect.rs index 95ad3176ca..a4091df792 100644 --- a/tracing-mock/src/expect.rs +++ b/tracing-mock/src/expect.rs @@ -1,7 +1,7 @@ use std::fmt; use crate::{ - ancestry::Ancestry, + ancestry::ExpectedAncestry, event::ExpectedEvent, field::{ExpectedField, ExpectedFields, ExpectedValue}, span::{ExpectedId, ExpectedSpan, NewSpan}, @@ -72,25 +72,25 @@ pub fn id() -> ExpectedId { } /// Convenience function that returns [`Ancestry::IsContextualRoot`]. -pub fn is_contextual_root() -> Ancestry { - Ancestry::IsContextualRoot +pub fn is_contextual_root() -> ExpectedAncestry { + ExpectedAncestry::IsContextualRoot } /// Convenience function that returns [`Ancestry::HasContextualParent`] with /// provided name. -pub fn has_contextual_parent>(name: S) -> Ancestry { - Ancestry::HasContextualParent(name.into()) +pub fn has_contextual_parent>(span: S) -> ExpectedAncestry { + ExpectedAncestry::HasContextualParent(span.into()) } /// Convenience function that returns [`Ancestry::IsExplicitRoot`]. -pub fn is_explicit_root() -> Ancestry { - Ancestry::IsExplicitRoot +pub fn is_explicit_root() -> ExpectedAncestry { + ExpectedAncestry::IsExplicitRoot } /// Convenience function that returns [`Ancestry::HasExplicitParent`] with /// provided name. -pub fn has_explicit_parent>(name: S) -> Ancestry { - Ancestry::HasExplicitParent(name.into()) +pub fn has_explicit_parent>(span: S) -> ExpectedAncestry { + ExpectedAncestry::HasExplicitParent(span.into()) } impl Expect { diff --git a/tracing-mock/src/metadata.rs b/tracing-mock/src/metadata.rs index 9d2d341145..d33ca209cb 100644 --- a/tracing-mock/src/metadata.rs +++ b/tracing-mock/src/metadata.rs @@ -9,48 +9,69 @@ pub(crate) struct ExpectedMetadata { } impl ExpectedMetadata { + /// Checks the given metadata against this expected metadata and panics if + /// there is a mismatch. + /// + /// The context `ctx` should fit into the followint sentence: + /// + /// > expected {ctx} named `expected_name`, but got one named `actual_name` + /// + /// Examples could be: + /// * a new span + /// * to enter a span + /// * an event + /// + /// # Panics + /// + /// This method will panic if any of the expectations that have been + /// specified are noto met. + /// pub(crate) fn check( &self, actual: &Metadata<'_>, - ctx: fmt::Arguments<'_>, + ctx: impl fmt::Display, collector_name: &str, ) { if let Some(ref expected_name) = self.name { - let name = actual.name(); + let actual_name = actual.name(); assert!( - expected_name == name, - "\n[{}] expected {} to be named `{}`, but got one named `{}`", - collector_name, - ctx, - expected_name, - name + expected_name == actual_name, + "{}", + format_args!( + "\n[{collector_name}] expected {ctx} named `{expected_name}`,\n\ + [{collector_name}] but got one named `{actual_name}` instead." + ), ) } if let Some(ref expected_level) = self.level { - let level = actual.level(); + let actual_level = actual.level(); assert!( - expected_level == level, - "\n[{}] expected {} to be at level `{:?}`, but it was at level `{:?}` instead", - collector_name, - ctx, - expected_level, - level, + expected_level == actual_level, + "{}", + format_args!( + "\n[{collector_name}] expected {ctx} at level `{expected_level:?}`,\n\ + [{collector_name}] but got one at level `{actual_level:?}` instead." + ), ) } if let Some(ref expected_target) = self.target { - let target = actual.target(); + let actual_target = actual.target(); assert!( - expected_target == target, - "\n[{}] expected {} to have target `{}`, but it had target `{}` instead", - collector_name, - ctx, - expected_target, - target, + expected_target == actual_target, + "{}", + format_args!( + "\n[{collector_name}] expected {ctx} with target `{expected_target}`,\n\ + [{collector_name}] but got one with target `{actual_target}` instead." + ), ) } } + + pub(crate) fn has_expectations(&self) -> bool { + self.name.is_some() || self.level.is_some() || self.target.is_some() + } } impl fmt::Display for ExpectedMetadata { diff --git a/tracing-mock/src/span.rs b/tracing-mock/src/span.rs index 34568551b3..fc716bd7c6 100644 --- a/tracing-mock/src/span.rs +++ b/tracing-mock/src/span.rs @@ -111,7 +111,9 @@ //! [`expect::span`]: fn@crate::expect::span #![allow(missing_docs)] use crate::{ - ancestry::Ancestry, collector::SpanState, expect, field::ExpectedFields, + ancestry::{ActualAncestry, ExpectedAncestry}, + expect, + field::ExpectedFields, metadata::ExpectedMetadata, }; use std::{ @@ -175,7 +177,7 @@ impl From<&ExpectedSpan> for ExpectedSpan { pub struct NewSpan { pub(crate) span: ExpectedSpan, pub(crate) fields: ExpectedFields, - pub(crate) ancestry: Option, + pub(crate) ancestry: Option, } pub fn named(name: I) -> ExpectedSpan @@ -185,6 +187,36 @@ where expect::span().named(name) } +pub(crate) struct ActualSpan { + id: tracing_core::span::Id, + metadata: Option<&'static tracing_core::Metadata<'static>>, +} + +impl ActualSpan { + pub(crate) fn new( + id: tracing_core::span::Id, + metadata: Option<&'static tracing_core::Metadata<'static>>, + ) -> Self { + Self { id, metadata } + } + + /// The Id of the actual span. + pub(crate) fn id(&self) -> tracing_core::span::Id { + self.id.clone() + } + + /// The metadata for the actual span if it is available. + pub(crate) fn metadata(&self) -> Option<&'static tracing_core::Metadata<'static>> { + self.metadata + } +} + +impl From<&tracing_core::span::Id> for ActualSpan { + fn from(id: &tracing_core::span::Id) -> Self { + Self::new(id.clone(), None) + } +} + /// A mock span ID. /// /// This ID makes it possible to link together calls to different @@ -535,9 +567,35 @@ impl ExpectedSpan { /// /// # Examples /// - /// If `expect::has_explicit_parent("parent_name")` is passed - /// `with_ancestry` then the provided string is the name of the explicit - /// parent span to expect. + /// An explicit or contextual parent can be matched on an `ExpectedSpan`. + /// + /// ``` + /// use tracing_mock::{collector, expect}; + /// + /// let parent = expect::span() + /// .named("parent_span") + /// .with_target("custom-target") + /// .at_level(tracing::Level::INFO); + /// let span = expect::span() + /// .with_ancestry(expect::has_explicit_parent(&parent)); + /// + /// let (collector, handle) = collector::mock() + /// .new_span(&parent) + /// .new_span(span) + /// .run_with_handle(); + /// + /// tracing::collect::with_default(collector, || { + /// let parent = tracing::info_span!(target: "custom-target", "parent_span"); + /// tracing::info_span!(parent: parent.id(), "span"); + /// }); + /// + /// handle.assert_finished(); + /// ``` + /// + /// The functions `expect::has_explicit_parent` and + /// `expect::has_contextual_parent` take `Into`, so a string + /// passed directly will match on a span with that name, or an + /// [`ExpectedId`] can be passed to match a span with that Id. /// /// ``` /// use tracing_mock::{collector, expect}; @@ -653,7 +711,7 @@ impl ExpectedSpan { /// [`MockCollector::enter`]: fn@crate::collector::MockCollector::enter /// [`MockCollector::exit`]: fn@crate::collector::MockCollector::exit /// [`MockCollector::new_span`]: fn@crate::collector::MockCollector::new_span - pub fn with_ancestry(self, ancestry: Ancestry) -> NewSpan { + pub fn with_ancestry(self, ancestry: ExpectedAncestry) -> NewSpan { NewSpan { ancestry: Some(ancestry), span: self, @@ -733,6 +791,10 @@ impl ExpectedSpan { } } + pub(crate) fn id(&self) -> Option<&ExpectedId> { + self.id.as_ref() + } + pub(crate) fn name(&self) -> Option<&str> { self.metadata.name.as_ref().map(String::as_ref) } @@ -745,16 +807,26 @@ impl ExpectedSpan { self.metadata.target.as_deref() } - pub(crate) fn check(&self, actual: &SpanState, collector_name: &str) { - let meta = actual.metadata(); - let name = meta.name(); - + pub(crate) fn check(&self, actual: &ActualSpan, ctx: impl fmt::Display, collector_name: &str) { if let Some(expected_id) = &self.id { - expected_id.check(actual.id(), format_args!("span `{}`", name), collector_name); + expected_id.check(&actual.id(), format_args!("{ctx} a span"), collector_name); } - self.metadata - .check(meta, format_args!("span `{}`", name), collector_name); + match actual.metadata() { + Some(actual_metadata) => self.metadata.check(actual_metadata, ctx, collector_name), + None => { + if self.metadata.has_expectations() { + panic!( + "{}", + format_args!( + "[{collector_name}] expected {ctx} a span with valid metadata, \ + but got one with unknown Id={actual_id}", + actual_id = actual.id().into_u64() + ) + ); + } + } + } } } @@ -762,6 +834,10 @@ impl fmt::Debug for ExpectedSpan { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut s = f.debug_struct("MockSpan"); + if let Some(id) = self.id() { + s.field("id", &id); + } + if let Some(name) = self.name() { s.field("name", &name); } @@ -807,7 +883,7 @@ impl NewSpan { /// /// For more information and examples, see the documentation on /// [`ExpectedSpan::with_ancestry`]. - pub fn with_ancestry(self, ancestry: Ancestry) -> NewSpan { + pub fn with_ancestry(self, ancestry: ExpectedAncestry) -> NewSpan { NewSpan { ancestry: Some(ancestry), ..self @@ -833,14 +909,12 @@ impl NewSpan { pub(crate) fn check( &mut self, span: &tracing_core::span::Attributes<'_>, - get_ancestry: impl FnOnce() -> Ancestry, + get_ancestry: impl FnOnce() -> ActualAncestry, collector_name: &str, ) { let meta = span.metadata(); let name = meta.name(); - self.span - .metadata - .check(meta, format_args!("span `{}`", name), collector_name); + self.span.metadata.check(meta, "a new span", collector_name); let mut checker = self.fields.checker(name, collector_name); span.record(&mut checker); checker.finish(); @@ -902,6 +976,12 @@ impl PartialEq for ExpectedId { impl Eq for ExpectedId {} +impl fmt::Debug for ExpectedId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("ExpectedId").field(&self.inner).finish() + } +} + impl ExpectedId { const UNSET: u64 = 0; @@ -921,21 +1001,33 @@ impl ExpectedId { Ok(()) } - pub(crate) fn check(&self, actual: u64, ctx: fmt::Arguments<'_>, collector_name: &str) { - let id = self.inner.load(Ordering::Relaxed); + pub(crate) fn check( + &self, + actual: &tracing_core::span::Id, + ctx: fmt::Arguments<'_>, + collector_name: &str, + ) { + let expected_id = self.inner.load(Ordering::Relaxed); + let actual_id = actual.into_u64(); assert!( - id != Self::UNSET, - "\n[{}] expected {} to have expected ID set, but it hasn't been, \ - perhaps this `ExpectedId` wasn't used in a call to `MockCollector::new_span()`?", - collector_name, - ctx, + expected_id != Self::UNSET, + "{}", + format!( + "\n[{collector_name}] expected {ctx} with an expected Id set,\n\ + [{collector_name}] but it hasn't been, perhaps this `ExpectedId` \ + wasn't used in a call to `new_span()`?" + ) ); assert_eq!( - id, actual, - "\n[{}] expected {} to have ID `{}`, but it has `{}` instead", - collector_name, ctx, id, actual, + expected_id, + actual_id, + "{}", + format_args!( + "\n[{collector_name}] expected {ctx} with Id `{expected_id}`,\n\ + [{collector_name}] but got one with Id `{actual_id}` instead", + ) ); } } diff --git a/tracing-mock/src/subscriber.rs b/tracing-mock/src/subscriber.rs index 16ed3a59f8..034b129a14 100644 --- a/tracing-mock/src/subscriber.rs +++ b/tracing-mock/src/subscriber.rs @@ -40,11 +40,11 @@ //! .named("my_span"); //! let (subscriber, handle) = subscriber::mock() //! // Enter a matching span -//! .enter(&span) +//! .enter(span.clone()) //! // Record an event with message "collect parting message" //! .event(expect::event().with_fields(expect::message("say hello"))) //! // Exit a matching span -//! .exit(&span) +//! .exit(span) //! // Expect no further messages to be recorded //! .only() //! // Return the collector and handle @@ -82,11 +82,11 @@ //! .named("my_span"); //! let (subscriber, handle) = subscriber::mock() //! // Enter a matching span -//! .enter(&span) +//! .enter(span.clone()) //! // Record an event with message "collect parting message" //! .event(expect::event().with_fields(expect::message("say hello"))) //! // Exit a matching span -//! .exit(&span) +//! .exit(span) //! // Expect no further messages to be recorded //! .only() //! // Return the collector and handle @@ -116,11 +116,11 @@ //! //! [`Subscribe`]: trait@tracing_subscriber::subscribe::Subscribe use crate::{ - ancestry::{get_ancestry, Ancestry, HasAncestry}, + ancestry::{get_ancestry, ActualAncestry, HasAncestry}, collector::MockHandle, event::ExpectedEvent, expect::Expect, - span::{ExpectedSpan, NewSpan}, + span::{ActualSpan, ExpectedSpan, NewSpan}, }; use tracing_core::{ span::{Attributes, Id, Record}, @@ -153,11 +153,11 @@ use std::{ /// .named("my_span"); /// let (subscriber, handle) = subscriber::mock() /// // Enter a matching span -/// .enter(&span) +/// .enter(span.clone()) /// // Record an event with message "collect parting message" /// .event(expect::event().with_fields(expect::message("say hello"))) /// // Exit a matching span -/// .exit(&span) +/// .exit(span) /// // Expect no further messages to be recorded /// .only() /// // Return the collector and handle @@ -505,8 +505,8 @@ impl MockSubscriberBuilder { /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (subscriber, handle) = subscriber::mock() - /// .enter(&span) - /// .exit(&span) + /// .enter(span.clone()) + /// .exit(span) /// .only() /// .run_with_handle(); /// @@ -533,8 +533,8 @@ impl MockSubscriberBuilder { /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (subscriber, handle) = subscriber::mock() - /// .enter(&span) - /// .exit(&span) + /// .enter(span.clone()) + /// .exit(span) /// .only() /// .run_with_handle(); /// @@ -553,11 +553,8 @@ impl MockSubscriberBuilder { /// /// [`exit`]: fn@Self::exit /// [`only`]: fn@Self::only - pub fn enter(mut self, span: S) -> Self - where - S: Into, - { - self.expected.push_back(Expect::Enter(span.into())); + pub fn enter(mut self, span: ExpectedSpan) -> Self { + self.expected.push_back(Expect::Enter(span)); self } @@ -585,8 +582,8 @@ impl MockSubscriberBuilder { /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (subscriber, handle) = subscriber::mock() - /// .enter(&span) - /// .exit(&span) + /// .enter(span.clone()) + /// .exit(span) /// .only() /// .run_with_handle(); /// @@ -612,8 +609,8 @@ impl MockSubscriberBuilder { /// .at_level(tracing::Level::INFO) /// .named("the span we're testing"); /// let (subscriber, handle) = subscriber::mock() - /// .enter(&span) - /// .exit(&span) + /// .enter(span.clone()) + /// .exit(span) /// .only() /// .run_with_handle(); /// @@ -633,11 +630,8 @@ impl MockSubscriberBuilder { /// [`enter`]: fn@Self::enter /// [`MockHandle::assert_finished`]: fn@crate::collector::MockHandle::assert_finished /// [`Span::enter`]: fn@tracing::Span::enter - pub fn exit(mut self, span: S) -> Self - where - S: Into, - { - self.expected.push_back(Expect::Exit(span.into())); + pub fn exit(mut self, span: ExpectedSpan) -> Self { + self.expected.push_back(Expect::Exit(span)); self } @@ -779,66 +773,16 @@ impl MockSubscriberBuilder { } } -impl MockSubscriber { - fn check_span_ref<'spans, S>( - &self, - expected: &ExpectedSpan, - actual: &SpanRef<'spans, S>, - what_happened: impl fmt::Display, - ) where - S: LookupSpan<'spans>, - { - if let Some(exp_name) = expected.name() { - assert_eq!( - actual.name(), - exp_name, - "\n[{}] expected {} a span named {:?}\n\ - [{}] but it was named {:?} instead (span {} {:?})", - self.name, - what_happened, - exp_name, - self.name, - actual.name(), - actual.name(), - actual.id() - ); - } - - if let Some(exp_level) = expected.level() { - let actual_level = actual.metadata().level(); - assert_eq!( - actual_level, - &exp_level, - "\n[{}] expected {} a span at {:?}\n\ - [{}] but it was at {:?} instead (span {} {:?})", - self.name, - what_happened, - exp_level, - self.name, - actual_level, - actual.name(), - actual.id(), - ); - } - - if let Some(exp_target) = expected.target() { - let actual_target = actual.metadata().target(); - assert_eq!( - actual_target, - exp_target, - "\n[{}] expected {} a span with target {:?}\n\ - [{}] but it had the target {:?} instead (span {} {:?})", - self.name, - what_happened, - exp_target, - self.name, - actual_target, - actual.name(), - actual.id(), - ); - } +impl<'a, S> From<&SpanRef<'a, S>> for ActualSpan +where + S: LookupSpan<'a>, +{ + fn from(span_ref: &SpanRef<'a, S>) -> Self { + Self::new(span_ref.id(), Some(span_ref.metadata())) } +} +impl MockSubscriber { fn check_event_scope( &self, current_scope: Option>, @@ -857,10 +801,10 @@ impl MockSubscriber { actual.id(), expected ); - self.check_span_ref( - expected, - &actual, + expected.check( + &(&actual).into(), format_args!("the {}th span in the event's scope to be", i), + &self.name, ); i += 1; } @@ -956,7 +900,7 @@ where match self.expected.lock().unwrap().pop_front() { None => {} Some(Expect::Enter(ref expected_span)) => { - self.check_span_ref(expected_span, &span, "to enter"); + expected_span.check(&(&span).into(), "to enter", &self.name); } Some(ex) => ex.bad(&self.name, format_args!("entered span {:?}", span.name())), } @@ -977,7 +921,7 @@ where match self.expected.lock().unwrap().pop_front() { None => {} Some(Expect::Exit(ref expected_span)) => { - self.check_span_ref(expected_span, &span, "to exit"); + expected_span.check(&(&span).into(), "to exit", &self.name); let curr = self.current.lock().unwrap().pop(); assert_eq!( Some(id), @@ -1014,7 +958,7 @@ where // as failing the assertion can cause a double panic. if !::std::thread::panicking() { if let Some(ref span) = span { - self.check_span_ref(expected_span, span, "to close"); + expected_span.check(&span.into(), "to close a span", &self.name); } } true @@ -1043,14 +987,14 @@ where } } -fn context_get_ancestry(item: impl HasAncestry, ctx: &Context<'_, C>) -> Ancestry +fn context_get_ancestry(item: impl HasAncestry, ctx: &Context<'_, C>) -> ActualAncestry where C: Collect + for<'a> LookupSpan<'a>, { get_ancestry( item, || ctx.lookup_current().map(|s| s.id()), - |span_id| ctx.span(span_id).map(|span| span.name()), + |span_id| ctx.span(span_id).map(|span| (&span).into()), ) } diff --git a/tracing-mock/tests/event_ancestry.rs b/tracing-mock/tests/event_ancestry.rs index 6bd253d016..0d9db87588 100644 --- a/tracing-mock/tests/event_ancestry.rs +++ b/tracing-mock/tests/event_ancestry.rs @@ -5,7 +5,7 @@ //! that an event has a specific contextual or explicit parent. //! //! [`ExpectedEvent`]: crate::event::ExpectedEvent -use tracing::collect::with_default; +use tracing::{collect::with_default, Level}; use tracing_mock::{collector, expect}; #[test] @@ -27,8 +27,8 @@ fn contextual_parent() { #[test] #[should_panic( - expected = "to have a contextual parent with name='contextual parent', but \ - actually has a contextual parent with name='another parent'" + expected = "to have a contextual parent span named `contextual parent`,\n\ + [contextual_parent_wrong_name] but got one named `another parent` instead." )] fn contextual_parent_wrong_name() { let event = expect::event().with_ancestry(expect::has_contextual_parent("contextual parent")); @@ -46,11 +46,53 @@ fn contextual_parent_wrong_name() { handle.assert_finished(); } +#[test] +#[should_panic(expected = "to have a contextual parent span a span with Id `1`,\n\ + [contextual_parent_wrong_id] but got one with Id `2` instead")] +fn contextual_parent_wrong_id() { + let id = expect::id(); + let event = expect::event().with_ancestry(expect::has_contextual_parent(&id)); + + let (collector, handle) = collector::mock() + .new_span(&id) + .enter(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + let _span = tracing::info_span!("contextual parent"); + let _guard = tracing::info_span!("another parent").entered(); + tracing::info!(field = &"value"); + }); + + handle.assert_finished(); +} + #[test] #[should_panic( - expected = "to have a contextual parent with name='contextual parent', but was actually a \ - contextual root" + expected = "to have a contextual parent span at level `Level(Info)`,\n\ + [contextual_parent_wrong_level] but got one at level `Level(Debug)` instead." )] +fn contextual_parent_wrong_level() { + let parent = expect::span().at_level(Level::INFO); + let event = expect::event().with_ancestry(expect::has_contextual_parent(parent)); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::debug_span!("contextual parent").entered(); + tracing::info!(field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic(expected = "to have a contextual parent span, but it is actually a \ + contextual root")] fn expect_contextual_parent_actual_contextual_root() { let event = expect::event().with_ancestry(expect::has_contextual_parent("contextual parent")); @@ -64,10 +106,8 @@ fn expect_contextual_parent_actual_contextual_root() { } #[test] -#[should_panic( - expected = "to have a contextual parent with name='contextual parent', but actually has an \ - explicit parent with name='explicit parent'" -)] +#[should_panic(expected = "to have a contextual parent span, but it actually has an \ + explicit parent span")] fn expect_contextual_parent_actual_explicit_parent() { let event = expect::event().with_ancestry(expect::has_contextual_parent("contextual parent")); @@ -82,10 +122,8 @@ fn expect_contextual_parent_actual_explicit_parent() { } #[test] -#[should_panic( - expected = "to have a contextual parent with name='contextual parent', but was actually an \ - explicit root" -)] +#[should_panic(expected = "to have a contextual parent span, but it is actually an \ + explicit root")] fn expect_contextual_parent_actual_explicit_root() { let event = expect::event().with_ancestry(expect::has_contextual_parent("contextual parent")); @@ -116,10 +154,7 @@ fn contextual_root() { } #[test] -#[should_panic( - expected = "to be a contextual root, but actually has a contextual parent with \ - name='contextual parent'" -)] +#[should_panic(expected = "to be a contextual root, but it actually has a contextual parent span")] fn expect_contextual_root_actual_contextual_parent() { let event = expect::event().with_ancestry(expect::is_contextual_root()); @@ -137,10 +172,7 @@ fn expect_contextual_root_actual_contextual_parent() { } #[test] -#[should_panic( - expected = "to be a contextual root, but actually has an explicit parent with \ - name='explicit parent'" -)] +#[should_panic(expected = "to be a contextual root, but it actually has an explicit parent span")] fn expect_contextual_root_actual_explicit_parent() { let event = expect::event().with_ancestry(expect::is_contextual_root()); @@ -155,7 +187,7 @@ fn expect_contextual_root_actual_explicit_parent() { } #[test] -#[should_panic(expected = "to be a contextual root, but was actually an explicit root")] +#[should_panic(expected = "to be a contextual root, but it is actually an explicit root")] fn expect_contextual_root_actual_explicit_root() { let event = expect::event().with_ancestry(expect::is_contextual_root()); @@ -188,8 +220,8 @@ fn explicit_parent() { #[test] #[should_panic( - expected = "to have an explicit parent with name='explicit parent', but actually has an \ - explicit parent with name='another parent'" + expected = "to have an explicit parent span named `explicit parent`,\n\ + [explicit_parent_wrong_name] but got one named `another parent` instead." )] fn explicit_parent_wrong_name() { let event = expect::event().with_ancestry(expect::has_explicit_parent("explicit parent")); @@ -205,10 +237,47 @@ fn explicit_parent_wrong_name() { } #[test] -#[should_panic( - expected = "to have an explicit parent with name='explicit parent', but actually has a \ - contextual parent with name='contextual parent'" -)] +#[should_panic(expected = "to have an explicit parent span a span with Id `1`,\n\ + [explicit_parent_wrong_id] but got one with Id `2` instead")] +fn explicit_parent_wrong_id() { + let id = expect::id(); + let event = expect::event().with_ancestry(expect::has_explicit_parent(&id)); + + let (collector, handle) = collector::mock() + .new_span(&id) + .new_span(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + let _span = tracing::info_span!("explicit parent"); + let another_span = tracing::info_span!("another parent"); + tracing::info!(parent: another_span.id(), field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic(expected = "to have an explicit parent span at level `Level(Info)`,\n\ + [explicit_parent_wrong_level] but got one at level `Level(Debug)` instead.")] +fn explicit_parent_wrong_level() { + let parent = expect::span().at_level(Level::INFO); + let event = expect::event().with_ancestry(expect::has_explicit_parent(parent)); + + let (collector, handle) = collector::mock().event(event).run_with_handle(); + + with_default(collector, || { + let span = tracing::debug_span!("explicit parent"); + tracing::info!(parent: span.id(), field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic(expected = "to have an explicit parent span, but it actually has a \ + contextual parent span")] fn expect_explicit_parent_actual_contextual_parent() { let event = expect::event().with_ancestry(expect::has_explicit_parent("explicit parent")); @@ -226,10 +295,8 @@ fn expect_explicit_parent_actual_contextual_parent() { } #[test] -#[should_panic( - expected = "to have an explicit parent with name='explicit parent', but was actually a \ - contextual root" -)] +#[should_panic(expected = "to have an explicit parent span, but it is actually a \ + contextual root")] fn expect_explicit_parent_actual_contextual_root() { let event = expect::event().with_ancestry(expect::has_explicit_parent("explicit parent")); @@ -243,10 +310,8 @@ fn expect_explicit_parent_actual_contextual_root() { } #[test] -#[should_panic( - expected = "to have an explicit parent with name='explicit parent', but was actually an \ - explicit root" -)] +#[should_panic(expected = "to have an explicit parent span, but it is actually an \ + explicit root")] fn expect_explicit_parent_actual_explicit_root() { let event = expect::event().with_ancestry(expect::has_explicit_parent("explicit parent")); @@ -281,10 +346,7 @@ fn explicit_root() { } #[test] -#[should_panic( - expected = "to be an explicit root, but actually has a contextual parent with \ - name='contextual parent'" -)] +#[should_panic(expected = "to be an explicit root, but it actually has a contextual parent span")] fn expect_explicit_root_actual_contextual_parent() { let event = expect::event().with_ancestry(expect::is_explicit_root()); @@ -302,7 +364,7 @@ fn expect_explicit_root_actual_contextual_parent() { } #[test] -#[should_panic(expected = "to be an explicit root, but was actually a contextual root")] +#[should_panic(expected = "to be an explicit root, but it is actually a contextual root")] fn expect_explicit_root_actual_contextual_root() { let event = expect::event().with_ancestry(expect::is_explicit_root()); @@ -316,9 +378,7 @@ fn expect_explicit_root_actual_contextual_root() { } #[test] -#[should_panic( - expected = "to be an explicit root, but actually has an explicit parent with name='explicit parent'" -)] +#[should_panic(expected = "to be an explicit root, but it actually has an explicit parent span")] fn expect_explicit_root_actual_explicit_parent() { let event = expect::event().with_ancestry(expect::is_explicit_root()); diff --git a/tracing-mock/tests/span_ancestry.rs b/tracing-mock/tests/span_ancestry.rs index 603c0a6b3c..0136e7cd14 100644 --- a/tracing-mock/tests/span_ancestry.rs +++ b/tracing-mock/tests/span_ancestry.rs @@ -6,7 +6,7 @@ //! //! [`ExpectedSpan`]: crate::span::ExpectedSpan //! -use tracing::collect::with_default; +use tracing::{collect::with_default, Level}; use tracing_mock::{collector, expect}; #[test] @@ -30,8 +30,8 @@ fn contextual_parent() { #[test] #[should_panic( - expected = "to have a contextual parent with name='contextual parent', but \ - actually has a contextual parent with name='another parent'" + expected = "to have a contextual parent span named `contextual parent`,\n\ + [contextual_parent_wrong_name] but got one named `another parent` instead." )] fn contextual_parent_wrong_name() { let span = expect::span() @@ -51,11 +51,58 @@ fn contextual_parent_wrong_name() { handle.assert_finished(); } +#[test] +#[should_panic(expected = "to have a contextual parent span a span with Id `1`,\n\ + [contextual_parent_wrong_id] but got one with Id `2` instead")] +fn contextual_parent_wrong_id() { + let id = expect::id(); + let span = expect::span() + .named("span") + .with_ancestry(expect::has_contextual_parent(&id)); + + let (collector, handle) = collector::mock() + .new_span(&id) + .new_span(expect::span()) + .enter(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let _span = tracing::info_span!("contextual parent"); + let _guard = tracing::info_span!("another parent").entered(); + tracing::info_span!("span"); + }); + + handle.assert_finished(); +} + #[test] #[should_panic( - expected = "to have a contextual parent with name='contextual parent', but was actually a \ - contextual root" + expected = "to have a contextual parent span at level `Level(Info)`,\n\ + [contextual_parent_wrong_level] but got one at level `Level(Debug)` instead." )] +fn contextual_parent_wrong_level() { + let parent = expect::span().at_level(Level::INFO); + let span = expect::span() + .named("span") + .with_ancestry(expect::has_contextual_parent(parent)); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::debug_span!("contextual parent").entered(); + tracing::info_span!("span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic(expected = "to have a contextual parent span, but it is actually a \ + contextual root")] fn expect_contextual_parent_actual_contextual_root() { let span = expect::span() .named("span") @@ -71,10 +118,8 @@ fn expect_contextual_parent_actual_contextual_root() { } #[test] -#[should_panic( - expected = "to have a contextual parent with name='contextual parent', but actually has an \ - explicit parent with name='explicit parent'" -)] +#[should_panic(expected = "to have a contextual parent span, but it actually has an \ + explicit parent span")] fn expect_contextual_parent_actual_explicit_parent() { let span = expect::span() .named("span") @@ -94,10 +139,8 @@ fn expect_contextual_parent_actual_explicit_parent() { } #[test] -#[should_panic( - expected = "to have a contextual parent with name='contextual parent', but was actually an \ - explicit root" -)] +#[should_panic(expected = "to have a contextual parent span, but it is actually an \ + explicit root")] fn expect_contextual_parent_actual_explicit_root() { let span = expect::span() .named("span") @@ -132,10 +175,7 @@ fn contextual_root() { } #[test] -#[should_panic( - expected = "to be a contextual root, but actually has a contextual parent with \ - name='contextual parent'" -)] +#[should_panic(expected = "to be a contextual root, but it actually has a contextual parent span")] fn expect_contextual_root_actual_contextual_parent() { let span = expect::span() .named("span") @@ -155,10 +195,7 @@ fn expect_contextual_root_actual_contextual_parent() { } #[test] -#[should_panic( - expected = "to be a contextual root, but actually has an explicit parent with \ - name='explicit parent'" -)] +#[should_panic(expected = "to be a contextual root, but it actually has an explicit parent span")] fn expect_contextual_root_actual_explicit_parent() { let span = expect::span() .named("span") @@ -178,7 +215,7 @@ fn expect_contextual_root_actual_explicit_parent() { } #[test] -#[should_panic(expected = "to be a contextual root, but was actually an explicit root")] +#[should_panic(expected = "to be a contextual root, but it is actually an explicit root")] fn expect_contextual_root_actual_explicit_root() { let span = expect::span() .named("span") @@ -218,8 +255,8 @@ fn explicit_parent() { #[test] #[should_panic( - expected = "to have an explicit parent with name='explicit parent', but actually has an \ - explicit parent with name='another parent'" + expected = "to have an explicit parent span named `explicit parent`,\n\ + [explicit_parent_wrong_name] but got one named `another parent` instead." )] fn explicit_parent_wrong_name() { let span = expect::span() @@ -240,10 +277,54 @@ fn explicit_parent_wrong_name() { } #[test] -#[should_panic( - expected = "to have an explicit parent with name='explicit parent', but actually has a \ - contextual parent with name='contextual parent'" -)] +#[should_panic(expected = "to have an explicit parent span a span with Id `1`,\n\ + [explicit_parent_wrong_id] but got one with Id `2` instead")] +fn explicit_parent_wrong_id() { + let id = expect::id(); + let span = expect::span() + .named("span") + .with_ancestry(expect::has_explicit_parent(&id)); + + let (collector, handle) = collector::mock() + .new_span(&id) + .new_span(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let _span = tracing::info_span!("explicit parent"); + let another_span = tracing::info_span!("another parent"); + tracing::info_span!(parent: another_span.id(), "span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic(expected = "to have an explicit parent span at level `Level(Info)`,\n\ + [explicit_parent_wrong_level] but got one at level `Level(Debug)` instead.")] +fn explicit_parent_wrong_level() { + let parent = expect::span().at_level(Level::INFO); + let span = expect::span() + .named("span") + .with_ancestry(expect::has_explicit_parent(parent)); + + let (collector, handle) = collector::mock() + .new_span(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let span = tracing::debug_span!("explicit parent"); + tracing::info_span!(parent: span.id(), "span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic(expected = "to have an explicit parent span, but it actually has a \ + contextual parent span")] fn expect_explicit_parent_actual_contextual_parent() { let span = expect::span() .named("span") @@ -263,10 +344,8 @@ fn expect_explicit_parent_actual_contextual_parent() { } #[test] -#[should_panic( - expected = "to have an explicit parent with name='explicit parent', but was actually a \ - contextual root" -)] +#[should_panic(expected = "to have an explicit parent span, but it is actually a \ + contextual root")] fn expect_explicit_parent_actual_contextual_root() { let span = expect::span() .named("span") @@ -282,10 +361,8 @@ fn expect_explicit_parent_actual_contextual_root() { } #[test] -#[should_panic( - expected = "to have an explicit parent with name='explicit parent', but was actually an \ - explicit root" -)] +#[should_panic(expected = "to have an explicit parent span, but it is actually an \ + explicit root")] fn expect_explicit_parent_actual_explicit_root() { let span = expect::span() .named("span") @@ -325,10 +402,7 @@ fn explicit_root() { } #[test] -#[should_panic( - expected = "to be an explicit root, but actually has a contextual parent with \ - name='contextual parent'" -)] +#[should_panic(expected = "to be an explicit root, but it actually has a contextual parent span")] fn expect_explicit_root_actual_contextual_parent() { let span = expect::span() .named("span") @@ -348,7 +422,7 @@ fn expect_explicit_root_actual_contextual_parent() { } #[test] -#[should_panic(expected = "to be an explicit root, but was actually a contextual root")] +#[should_panic(expected = "to be an explicit root, but it is actually a contextual root")] fn expect_explicit_root_actual_contextual_root() { let span = expect::span() .named("span") @@ -364,9 +438,7 @@ fn expect_explicit_root_actual_contextual_root() { } #[test] -#[should_panic( - expected = "to be an explicit root, but actually has an explicit parent with name='explicit parent'" -)] +#[should_panic(expected = "to be an explicit root, but it actually has an explicit parent span")] fn expect_explicit_root_actual_explicit_parent() { let span = expect::span() .named("span") From 963a05b92388bf081c6d3b6701c3976bbeb4392f Mon Sep 17 00:00:00 2001 From: Hayden Stainsby Date: Tue, 29 Oct 2024 16:16:42 +0100 Subject: [PATCH 3/3] fix broken links in docs --- tracing-mock/src/ancestry.rs | 2 +- tracing-mock/src/event.rs | 7 ++++--- tracing-mock/src/expect.rs | 8 ++++---- tracing-mock/src/span.rs | 11 ++++++----- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/tracing-mock/src/ancestry.rs b/tracing-mock/src/ancestry.rs index 2b96c289b3..817e30fef0 100644 --- a/tracing-mock/src/ancestry.rs +++ b/tracing-mock/src/ancestry.rs @@ -1,6 +1,6 @@ //! Define the ancestry of an event or span. //! -//! See the documentation on the [`Ancestry`] enum for further details. +//! See the documentation on the [`ExpectedAncestry`] enum for further details. use tracing_core::{ span::{self, Attributes}, diff --git a/tracing-mock/src/event.rs b/tracing-mock/src/event.rs index 1e52b72320..c9445a107e 100644 --- a/tracing-mock/src/event.rs +++ b/tracing-mock/src/event.rs @@ -258,9 +258,10 @@ impl ExpectedEvent { } } - /// Configures this `ExpectedEvent` to expect the specified [`Ancestry`]. - /// An event's ancestry indicates whether is has a parent or is a root, and - /// whether the parent is explicitly or contextually assigned. + /// Configures this `ExpectedEvent` to expect the specified + /// [`ExpectedAncestry`]. An event's ancestry indicates whether is has a + /// parent or is a root, and whether the parent is explicitly or + /// contextually assigned. /// /// An _explicit_ parent span is one passed to the `event!` macro in the /// `parent:` field. If no `parent:` field is specified, then the event diff --git a/tracing-mock/src/expect.rs b/tracing-mock/src/expect.rs index a4091df792..aebcc9eecd 100644 --- a/tracing-mock/src/expect.rs +++ b/tracing-mock/src/expect.rs @@ -71,23 +71,23 @@ pub fn id() -> ExpectedId { ExpectedId::new_unset() } -/// Convenience function that returns [`Ancestry::IsContextualRoot`]. +/// Convenience function that returns [`ExpectedAncestry::IsContextualRoot`]. pub fn is_contextual_root() -> ExpectedAncestry { ExpectedAncestry::IsContextualRoot } -/// Convenience function that returns [`Ancestry::HasContextualParent`] with +/// Convenience function that returns [`ExpectedAncestry::HasContextualParent`] with /// provided name. pub fn has_contextual_parent>(span: S) -> ExpectedAncestry { ExpectedAncestry::HasContextualParent(span.into()) } -/// Convenience function that returns [`Ancestry::IsExplicitRoot`]. +/// Convenience function that returns [`ExpectedAncestry::IsExplicitRoot`]. pub fn is_explicit_root() -> ExpectedAncestry { ExpectedAncestry::IsExplicitRoot } -/// Convenience function that returns [`Ancestry::HasExplicitParent`] with +/// Convenience function that returns [`ExpectedAncestry::HasExplicitParent`] with /// provided name. pub fn has_explicit_parent>(span: S) -> ExpectedAncestry { ExpectedAncestry::HasExplicitParent(span.into()) diff --git a/tracing-mock/src/span.rs b/tracing-mock/src/span.rs index fc716bd7c6..56406ed422 100644 --- a/tracing-mock/src/span.rs +++ b/tracing-mock/src/span.rs @@ -547,9 +547,10 @@ impl ExpectedSpan { } } - /// Configures this `ExpectedSpan` to expect the specified [`Ancestry`]. A - /// span's ancestry indicates whether it has a parent or is a root span - /// and whether the parent is explitly or contextually assigned. + /// Configures this `ExpectedSpan` to expect the specified + /// [`ExpectedAncestry`]. A span's ancestry indicates whether it has a + /// parent or is a root span and whether the parent is explitly or + /// contextually assigned. /// /// **Note**: This method returns a [`NewSpan`] and as such, this /// expectation can only be validated when expecting a new span via @@ -877,8 +878,8 @@ where } impl NewSpan { - /// Configures this `NewSpan` to expect the specified [`Ancestry`]. A - /// span's ancestry indicates whether it has a parent or is a root span + /// Configures this `NewSpan` to expect the specified [`ExpectedAncestry`]. + /// A span's ancestry indicates whether it has a parent or is a root span /// and whether the parent is explitly or contextually assigned. /// /// For more information and examples, see the documentation on