diff --git a/tracing-attributes/tests/parents.rs b/tracing-attributes/tests/parents.rs index c33e44a74f..ab87f333f1 100644 --- a/tracing-attributes/tests/parents.rs +++ b/tracing-attributes/tests/parents.rs @@ -18,26 +18,15 @@ fn default_parent_test() { let child = expect::span().named("with_default_parent"); let (collector, handle) = collector::mock() - .new_span( - contextual_parent - .clone() - .with_contextual_parent(None) - .with_explicit_parent(None), - ) - .new_span( - child - .clone() - .with_contextual_parent(Some("contextual_parent")) - .with_explicit_parent(None), - ) + .new_span(contextual_parent.clone().with_contextual_parent(None)) + .new_span(child.clone().with_contextual_parent(None)) .enter(child.clone()) .exit(child.clone()) .enter(contextual_parent.clone()) .new_span( child .clone() - .with_contextual_parent(Some("contextual_parent")) - .with_explicit_parent(None), + .with_contextual_parent(Some("contextual_parent")), ) .enter(child.clone()) .exit(child) @@ -65,24 +54,10 @@ fn explicit_parent_test() { let child = expect::span().named("with_explicit_parent"); let (collector, handle) = collector::mock() - .new_span( - contextual_parent - .clone() - .with_contextual_parent(None) - .with_explicit_parent(None), - ) - .new_span( - explicit_parent - .with_contextual_parent(None) - .with_explicit_parent(None), - ) + .new_span(contextual_parent.clone().with_contextual_parent(None)) + .new_span(explicit_parent.with_contextual_parent(None)) .enter(contextual_parent.clone()) - .new_span( - child - .clone() - .with_contextual_parent(Some("contextual_parent")) - .with_explicit_parent(Some("explicit_parent")), - ) + .new_span(child.clone().with_explicit_parent(Some("explicit_parent"))) .enter(child.clone()) .exit(child) .exit(contextual_parent) diff --git a/tracing-mock/src/collector.rs b/tracing-mock/src/collector.rs index a91cdd332d..b29f297aab 100644 --- a/tracing-mock/src/collector.rs +++ b/tracing-mock/src/collector.rs @@ -141,6 +141,7 @@ use crate::{ event::ExpectedEvent, expect::Expect, field::ExpectedFields, + parent::Parent, span::{ExpectedSpan, NewSpan}, }; use std::{ @@ -1034,16 +1035,36 @@ where ) } } - let get_parent_name = || { - let stack = self.current.lock().unwrap(); + + let get_parent = || { let spans = self.spans.lock().unwrap(); - event - .parent() - .and_then(|id| spans.get(id)) - .or_else(|| stack.last().and_then(|id| spans.get(id))) - .map(|s| s.name.to_string()) + + if event.is_contextual() { + let stack = self.current.lock().unwrap(); + if let Some(parent_id) = stack.last() { + let contextual_parent = spans.get(parent_id).expect( + "tracing-mock: contextual parent cannot \ + be looked up by ID. Was it recorded correctly?", + ); + Parent::Contextual(contextual_parent.name.to_string()) + } else { + Parent::ContextualRoot + } + } else if event.is_root() { + Parent::ExplicitRoot + } else { + let parent_id = event.parent().expect( + "tracing-mock: is_contextual=false is_root=false \ + but no explicit parent found. This is a bug!", + ); + let explicit_parent = spans.get(parent_id).expect( + "tracing-mock: explicit parent cannot be looked \ + up by ID. Is the provided Span ID valid: {parent_id}", + ); + Parent::Explicit(explicit_parent.name.to_string()) + } }; - expected.check(event, get_parent_name, &self.name); + expected.check(event, get_parent, &self.name); } Some(ex) => ex.bad(&self.name, format_args!("observed event {:#?}", event)), } @@ -1100,14 +1121,33 @@ where let mut spans = self.spans.lock().unwrap(); if was_expected { if let Expect::NewSpan(mut expected) = expected.pop_front().unwrap() { - let get_parent_name = || { - let stack = self.current.lock().unwrap(); - span.parent() - .and_then(|id| spans.get(id)) - .or_else(|| stack.last().and_then(|id| spans.get(id))) - .map(|s| s.name.to_string()) + let get_parent = || { + if span.is_contextual() { + let stack = self.current.lock().unwrap(); + if let Some(parent_id) = stack.last() { + let contextual_parent = spans.get(parent_id).expect( + "tracing-mock: contextual parent cannot \ + be looked up by ID. Was it recorded correctly?", + ); + Parent::Contextual(contextual_parent.name.to_string()) + } else { + Parent::ContextualRoot + } + } else if span.is_root() { + Parent::ExplicitRoot + } else { + let parent_id = span.parent().expect( + "tracing-mock: is_contextual=false is_root=false \ + but no explicit parent found. This is a bug!", + ); + let explicit_parent = spans.get(parent_id).expect( + "tracing-mock: explicit parent cannot be looked \ + up by ID. Is the provided Span ID valid: {parent_id}", + ); + Parent::Explicit(explicit_parent.name.to_string()) + } }; - expected.check(span, get_parent_name, &self.name); + expected.check(span, get_parent, &self.name); } } spans.insert( diff --git a/tracing-mock/src/event.rs b/tracing-mock/src/event.rs index 840867d019..9abeeb0c27 100644 --- a/tracing-mock/src/event.rs +++ b/tracing-mock/src/event.rs @@ -29,7 +29,7 @@ //! [`collector`]: mod@crate::collector //! [`expect::event`]: fn@crate::expect::event #![allow(missing_docs)] -use super::{expect, field, metadata::ExpectedMetadata, span, Parent}; +use super::{expect, field, metadata::ExpectedMetadata, parent::Parent, span}; use std::fmt; @@ -303,10 +303,12 @@ impl ExpectedEvent { /// .with_explicit_parent(None); /// /// let (collector, handle) = collector::mock() + /// .enter(expect::span()) /// .event(event) /// .run_with_handle(); /// /// with_default(collector, || { + /// let _guard = tracing::info_span!("contextual parent").entered(); /// tracing::info!(parent: None, field = &"value"); /// }); /// @@ -557,7 +559,7 @@ impl ExpectedEvent { pub(crate) fn check( &mut self, event: &tracing::Event<'_>, - get_parent_name: impl FnOnce() -> Option, + get_parent: impl FnOnce() -> Parent, collector_name: &str, ) { let meta = event.metadata(); @@ -578,13 +580,8 @@ impl ExpectedEvent { } if let Some(ref expected_parent) = self.parent { - let actual_parent = get_parent_name(); - expected_parent.check_parent_name( - actual_parent.as_deref(), - event.parent().cloned(), - event.metadata().name(), - collector_name, - ) + let actual_parent = get_parent(); + expected_parent.check(&actual_parent, event.metadata().name(), collector_name); } } } diff --git a/tracing-mock/src/lib.rs b/tracing-mock/src/lib.rs index 9fdeab5866..275c616aa8 100644 --- a/tracing-mock/src/lib.rs +++ b/tracing-mock/src/lib.rs @@ -4,92 +4,8 @@ pub mod event; pub mod expect; pub mod field; mod metadata; +mod parent; pub mod span; #[cfg(feature = "tracing-subscriber")] pub mod subscriber; - -#[derive(Debug, Eq, PartialEq)] -pub enum Parent { - ContextualRoot, - Contextual(String), - ExplicitRoot, - Explicit(String), -} - -impl Parent { - pub fn check_parent_name( - &self, - parent_name: Option<&str>, - provided_parent: Option, - ctx: impl std::fmt::Display, - collector_name: &str, - ) { - match self { - Parent::ExplicitRoot => { - assert!( - provided_parent.is_none(), - "[{}] expected {} to be an explicit root, but its parent was actually {:?} (name: {:?})", - collector_name, - ctx, - provided_parent, - parent_name, - ); - } - Parent::Explicit(expected_parent) => { - assert!( - provided_parent.is_some(), - "[{}] expected {} to have explicit parent {}, but it has no explicit parent", - collector_name, - ctx, - expected_parent, - ); - assert_eq!( - Some(expected_parent.as_ref()), - parent_name, - "[{}] expected {} to have explicit parent {}, but its parent was actually {:?} (name: {:?})", - collector_name, - ctx, - expected_parent, - provided_parent, - parent_name, - ); - } - Parent::ContextualRoot => { - assert!( - provided_parent.is_none(), - "[{}] expected {} to be a contextual root, but its parent was actually {:?} (name: {:?})", - collector_name, - ctx, - provided_parent, - parent_name, - ); - assert!( - parent_name.is_none(), - "[{}] expected {} to be contextual a root, but we were inside span {:?}", - collector_name, - ctx, - parent_name, - ); - } - Parent::Contextual(expected_parent) => { - assert!(provided_parent.is_none(), - "[{}] expected {} to have a contextual parent\nbut it has the explicit parent {:?} (name: {:?})", - collector_name, - ctx, - provided_parent, - parent_name, - ); - assert_eq!( - Some(expected_parent.as_ref()), - parent_name, - "[{}] expected {} to have contextual parent {:?}, but got {:?}", - collector_name, - ctx, - expected_parent, - parent_name, - ); - } - } - } -} diff --git a/tracing-mock/src/parent.rs b/tracing-mock/src/parent.rs new file mode 100644 index 0000000000..99230d278f --- /dev/null +++ b/tracing-mock/src/parent.rs @@ -0,0 +1,50 @@ +/// The parent of an event or span. +/// +/// This enum is used to represent the expected and the actual parent of an +/// event or a span. +#[derive(Debug, Eq, PartialEq)] +pub(crate) enum Parent { + /// The event or span is contextually a root - it has no parent. + ContextualRoot, + /// The event or span has a contextually assigned parent, with the specified name. + Contextual(String), + /// The event or span is explicitly a root, it was created with `parent: None`. + ExplicitRoot, + /// The event or span has an explicit parent with the specified name, it was created with + /// `parent: span_id`. + Explicit(String), +} + +impl Parent { + #[track_caller] + pub(crate) fn check( + &self, + actual_parent: &Parent, + ctx: impl std::fmt::Display, + collector_name: &str, + ) { + let expected_description = |parent: &Parent| match parent { + Self::ExplicitRoot => "be an explicit root".to_string(), + Self::Explicit(name) => format!("have an explicit parent with name='{name}'"), + Self::ContextualRoot => "be a contextual root".to_string(), + Self::Contextual(name) => format!("have a contextual parent with name='{name}'"), + }; + + let actual_description = |parent: &Parent| match parent { + Self::ExplicitRoot => "was actually an explicit root".to_string(), + Self::Explicit(name) => format!("actually has an explicit parent with name='{name}'"), + Self::ContextualRoot => "was actually a contextual root".to_string(), + Self::Contextual(name) => { + format!("actually has a contextual parent with name='{name}'") + } + }; + + assert_eq!( + self, + actual_parent, + "[{collector_name}] expected {ctx} to {expected_description}, but {actual_description}", + expected_description = expected_description(self), + actual_description = actual_description(actual_parent) + ); + } +} diff --git a/tracing-mock/src/span.rs b/tracing-mock/src/span.rs index 42ed3a603e..51a95d5120 100644 --- a/tracing-mock/src/span.rs +++ b/tracing-mock/src/span.rs @@ -92,7 +92,7 @@ //! [`expect::span`]: fn@crate::expect::span #![allow(missing_docs)] use crate::{ - collector::SpanState, expect, field::ExpectedFields, metadata::ExpectedMetadata, Parent, + collector::SpanState, expect, field::ExpectedFields, metadata::ExpectedMetadata, parent::Parent, }; use std::fmt; @@ -699,7 +699,7 @@ impl NewSpan { pub(crate) fn check( &mut self, span: &tracing_core::span::Attributes<'_>, - get_parent_name: impl FnOnce() -> Option, + get_parent: impl FnOnce() -> Parent, collector_name: &str, ) { let meta = span.metadata(); @@ -711,14 +711,13 @@ impl NewSpan { span.record(&mut checker); checker.finish(); - if let Some(expected_parent) = self.parent.as_ref() { - let actual_parent = get_parent_name(); - expected_parent.check_parent_name( - actual_parent.as_deref(), - span.parent().cloned(), + if let Some(ref expected_parent) = self.parent { + let actual_parent = get_parent(); + expected_parent.check( + &actual_parent, format_args!("span `{}`", name), collector_name, - ) + ); } } } diff --git a/tracing-mock/src/subscriber.rs b/tracing-mock/src/subscriber.rs index 6a8c536d55..9046c556ab 100644 --- a/tracing-mock/src/subscriber.rs +++ b/tracing-mock/src/subscriber.rs @@ -119,6 +119,7 @@ use crate::{ collector::MockHandle, event::ExpectedEvent, expect::Expect, + parent::Parent, span::{ExpectedSpan, NewSpan}, }; use tracing_core::{ @@ -905,8 +906,32 @@ where match self.expected.lock().unwrap().pop_front() { None => {} Some(Expect::Event(mut expected)) => { - let get_parent_name = || cx.event_span(event).map(|span| span.name().to_string()); - expected.check(event, get_parent_name, &self.name); + let get_parent = || { + if event.is_contextual() { + if let Some(parent) = cx.lookup_current() { + let contextual_parent = cx.span(&parent.id()).expect( + "tracing-mock: contextual parent cannot \ + be looked up by ID. Was it recorded correctly?", + ); + Parent::Contextual(contextual_parent.name().to_string()) + } else { + Parent::ContextualRoot + } + } else if event.is_root() { + Parent::ExplicitRoot + } else { + let parent_id = event.parent().expect( + "tracing-mock: is_contextual=false is_root=false \ + but no explicit parent found. This is a bug!", + ); + let explicit_parent = cx.span(parent_id).expect( + "tracing-mock: explicit parent cannot be looked \ + up by ID. Is the provided Span ID valid: {parent_id}?", + ); + Parent::Explicit(explicit_parent.name().to_string()) + } + }; + expected.check(event, get_parent, &self.name); if let Some(expected_scope) = expected.scope_mut() { self.check_event_scope(cx.event_scope(event), expected_scope); @@ -937,13 +962,32 @@ where let was_expected = matches!(expected.front(), Some(Expect::NewSpan(_))); if was_expected { if let Expect::NewSpan(mut expected) = expected.pop_front().unwrap() { - let get_parent_name = || { - span.parent() - .and_then(|id| cx.span(id)) - .or_else(|| cx.lookup_current()) - .map(|span| span.name().to_string()) + let get_parent = || { + if span.is_contextual() { + if let Some(parent) = cx.lookup_current() { + let contextual_parent = cx.span(&parent.id()).expect( + "tracing-mock: contextual parent cannot \ + be looked up by ID. Was it recorded correctly?", + ); + Parent::Contextual(contextual_parent.name().to_string()) + } else { + Parent::ContextualRoot + } + } else if span.is_root() { + Parent::ExplicitRoot + } else { + let parent_id = span.parent().expect( + "tracing-mock: is_contextual=false is_root=false \ + but no explicit parent found. This is a bug!", + ); + let explicit_parent = cx.span(parent_id).expect( + "tracing-mock: explicit parent cannot be looked \ + up by ID. Is the provided Span ID valid: {parent_id}?", + ); + Parent::Explicit(explicit_parent.name().to_string()) + } }; - expected.check(span, get_parent_name, &self.name); + expected.check(span, get_parent, &self.name); } } } diff --git a/tracing-mock/tests/event_parent.rs b/tracing-mock/tests/event_parent.rs new file mode 100644 index 0000000000..f09b1ae3fb --- /dev/null +++ b/tracing-mock/tests/event_parent.rs @@ -0,0 +1,346 @@ +//! Tests assertions for the parent made on [`ExpectedEvent`]. +//! +//! The tests in this module completely cover the positive and negative cases +//! when expecting that an event is a contextual or explicit root or expecting +//! that an event has a specific contextual or explicit parent. +//! +//! [`ExpectedEvent`]: crate::event::ExpectedEvent +use tracing::collect::with_default; +use tracing_mock::{collector, expect}; + +#[test] +fn contextual_parent() { + let event = expect::event().with_contextual_parent(Some("contextual parent")); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info!(field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have a contextual parent with name='contextual parent', but \ + actually has a contextual parent with name='another parent'" +)] +fn contextual_parent_wrong_name() { + let event = expect::event().with_contextual_parent(Some("contextual parent")); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + 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" +)] +fn expect_contextual_parent_actual_contextual_root() { + let event = expect::event().with_contextual_parent(Some("contextual parent")); + + let (collector, handle) = collector::mock().event(event).run_with_handle(); + + with_default(collector, || { + tracing::info!(field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have a contextual parent with name='contextual parent', but actually has an \ + explicit parent with name='explicit parent'" +)] +fn expect_contextual_parent_actual_explicit_parent() { + let event = expect::event().with_contextual_parent(Some("contextual parent")); + + let (collector, handle) = collector::mock().event(event).run_with_handle(); + + with_default(collector, || { + let span = tracing::info_span!("explicit parent"); + tracing::info!(parent: span.id(), field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have a contextual parent with name='contextual parent', but was actually an \ + explicit root" +)] +fn expect_contextual_parent_actual_explicit_root() { + let event = expect::event().with_contextual_parent(Some("contextual parent")); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info!(parent: None, field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +fn contextual_root() { + let event = expect::event().with_contextual_parent(None); + + let (collector, handle) = collector::mock().event(event).run_with_handle(); + + with_default(collector, || { + tracing::info!(field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to be a contextual root, but actually has a contextual parent with \ + name='contextual parent'" +)] +fn expect_contextual_root_actual_contextual_parent() { + let event = expect::event().with_contextual_parent(None); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info!(field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to be a contextual root, but actually has an explicit parent with \ + name='explicit parent'" +)] +fn expect_contextual_root_actual_explicit_parent() { + let event = expect::event().with_contextual_parent(None); + + let (collector, handle) = collector::mock().event(event).run_with_handle(); + + with_default(collector, || { + let span = tracing::info_span!("explicit parent"); + tracing::info!(parent: span.id(), field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic(expected = "to be a contextual root, but was actually an explicit root")] +fn expect_contextual_root_actual_explicit_root() { + let event = expect::event().with_contextual_parent(None); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info!(parent: None, field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +fn explicit_parent() { + let event = expect::event().with_explicit_parent(Some("explicit parent")); + + let (collector, handle) = collector::mock().event(event).run_with_handle(); + + with_default(collector, || { + let span = tracing::info_span!("explicit parent"); + tracing::info!(parent: span.id(), field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have an explicit parent with name='explicit parent', but actually has an \ + explicit parent with name='another parent'" +)] +fn explicit_parent_wrong_name() { + let event = expect::event().with_explicit_parent(Some("explicit parent")); + + let (collector, handle) = collector::mock().event(event).run_with_handle(); + + with_default(collector, || { + let span = tracing::info_span!("another parent"); + tracing::info!(parent: span.id(), field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have an explicit parent with name='explicit parent', but actually has a \ + contextual parent with name='contextual parent'" +)] +fn expect_explicit_parent_actual_contextual_parent() { + let event = expect::event().with_explicit_parent(Some("explicit parent")); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info!(field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have an explicit parent with name='explicit parent', but was actually a \ + contextual root" +)] +fn expect_explicit_parent_actual_contextual_root() { + let event = expect::event().with_explicit_parent(Some("explicit parent")); + + let (collector, handle) = collector::mock().event(event).run_with_handle(); + + with_default(collector, || { + tracing::info!(field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have an explicit parent with name='explicit parent', but was actually an \ + explicit root" +)] +fn expect_explicit_parent_actual_explicit_root() { + let event = expect::event().with_explicit_parent(Some("explicit parent")); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info!(parent: None, field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +fn explicit_root() { + let event = expect::event().with_explicit_parent(None); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info!(parent: None, field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to be an explicit root, but actually has a contextual parent with \ + name='contextual parent'" +)] +fn expect_explicit_root_actual_contextual_parent() { + let event = expect::event().with_explicit_parent(None); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .event(event) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info!(field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic(expected = "to be an explicit root, but was actually a contextual root")] +fn expect_explicit_root_actual_contextual_root() { + let event = expect::event().with_explicit_parent(None); + + let (collector, handle) = collector::mock().event(event).run_with_handle(); + + with_default(collector, || { + tracing::info!(field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to be an explicit root, but actually has an explicit parent with name='explicit parent'" +)] +fn expect_explicit_root_actual_explicit_parent() { + let event = expect::event().with_explicit_parent(None); + + let (collector, handle) = collector::mock().event(event).run_with_handle(); + + with_default(collector, || { + let span = tracing::info_span!("explicit parent"); + tracing::info!(parent: span.id(), field = &"value"); + }); + + handle.assert_finished(); +} + +#[test] +fn explicit_and_contextual_root_is_explicit() { + let event = expect::event().with_explicit_parent(None); + + let (collector, handle) = collector::mock().event(event).run_with_handle(); + + with_default(collector, || { + tracing::info!(parent: None, field = &"value"); + }); + + handle.assert_finished(); +} diff --git a/tracing-mock/tests/span_parent.rs b/tracing-mock/tests/span_parent.rs new file mode 100644 index 0000000000..9f5fb5e38a --- /dev/null +++ b/tracing-mock/tests/span_parent.rs @@ -0,0 +1,383 @@ +//! Tests assertions for the parent made on [`ExpectedSpan`]. +//! +//! The tests in this module completely cover the positive and negative cases +//! when expecting that a span is a contextual or explicit root or expecting +//! that a span has a specific contextual or explicit parent. +//! +//! [`ExpectedSpan`]: crate::span::ExpectedSpan +//! +use tracing::collect::with_default; +use tracing_mock::{collector, expect}; + +#[test] +fn contextual_parent() { + let span = expect::span() + .named("span") + .with_contextual_parent(Some("contextual parent")); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info_span!("span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have a contextual parent with name='contextual parent', but \ + actually has a contextual parent with name='another parent'" +)] +fn contextual_parent_wrong_name() { + let span = expect::span() + .named("span") + .with_contextual_parent(Some("contextual parent")); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + 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" +)] +fn expect_contextual_parent_actual_contextual_root() { + let span = expect::span() + .named("span") + .with_contextual_parent(Some("contextual parent")); + + let (collector, handle) = collector::mock().new_span(span).run_with_handle(); + + with_default(collector, || { + tracing::info_span!("span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have a contextual parent with name='contextual parent', but actually has an \ + explicit parent with name='explicit parent'" +)] +fn expect_contextual_parent_actual_explicit_parent() { + let span = expect::span() + .named("span") + .with_contextual_parent(Some("contextual parent")); + + let (collector, handle) = collector::mock() + .new_span(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let span = tracing::info_span!("explicit parent"); + tracing::info_span!(parent: span.id(), "span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have a contextual parent with name='contextual parent', but was actually an \ + explicit root" +)] +fn expect_contextual_parent_actual_explicit_root() { + let span = expect::span() + .named("span") + .with_contextual_parent(Some("contextual parent")); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info_span!(parent: None, "span"); + }); + + handle.assert_finished(); +} + +#[test] +fn contextual_root() { + let span = expect::span().named("span").with_contextual_parent(None); + + let (collector, handle) = collector::mock().new_span(span).run_with_handle(); + + with_default(collector, || { + tracing::info_span!("span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to be a contextual root, but actually has a contextual parent with \ + name='contextual parent'" +)] +fn expect_contextual_root_actual_contextual_parent() { + let span = expect::span().named("span").with_contextual_parent(None); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info_span!("span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to be a contextual root, but actually has an explicit parent with \ + name='explicit parent'" +)] +fn expect_contextual_root_actual_explicit_parent() { + let span = expect::span().named("span").with_contextual_parent(None); + + let (collector, handle) = collector::mock() + .new_span(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let span = tracing::info_span!("explicit parent"); + tracing::info_span!(parent: span.id(), "span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic(expected = "to be a contextual root, but was actually an explicit root")] +fn expect_contextual_root_actual_explicit_root() { + let span = expect::span().named("span").with_contextual_parent(None); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info_span!(parent: None, "span"); + }); + + handle.assert_finished(); +} + +#[test] +fn explicit_parent() { + let span = expect::span() + .named("span") + .with_explicit_parent(Some("explicit parent")); + + let (collector, handle) = collector::mock() + .new_span(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let span = tracing::info_span!("explicit parent"); + tracing::info_span!(parent: span.id(), "span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have an explicit parent with name='explicit parent', but actually has an \ + explicit parent with name='another parent'" +)] +fn explicit_parent_wrong_name() { + let span = expect::span() + .named("span") + .with_explicit_parent(Some("explicit parent")); + + let (collector, handle) = collector::mock() + .new_span(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let span = tracing::info_span!("another parent"); + tracing::info_span!(parent: span.id(), "span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have an explicit parent with name='explicit parent', but actually has a \ + contextual parent with name='contextual parent'" +)] +fn expect_explicit_parent_actual_contextual_parent() { + let span = expect::span() + .named("span") + .with_explicit_parent(Some("explicit parent")); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info_span!("span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have an explicit parent with name='explicit parent', but was actually a \ + contextual root" +)] +fn expect_explicit_parent_actual_contextual_root() { + let span = expect::span() + .named("span") + .with_explicit_parent(Some("explicit parent")); + + let (collector, handle) = collector::mock().new_span(span).run_with_handle(); + + with_default(collector, || { + tracing::info_span!("span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to have an explicit parent with name='explicit parent', but was actually an \ + explicit root" +)] +fn expect_explicit_parent_actual_explicit_root() { + let span = expect::span() + .named("span") + .with_explicit_parent(Some("explicit parent")); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info_span!(parent: None, "span"); + }); + + handle.assert_finished(); +} + +#[test] +fn explicit_root() { + let span = expect::span().named("span").with_explicit_parent(None); + + let (collector, handle) = collector::mock() + .new_span(expect::span()) + .enter(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info_span!(parent: None, "span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to be an explicit root, but actually has a contextual parent with \ + name='contextual parent'" +)] +fn expect_explicit_root_actual_contextual_parent() { + let span = expect::span().named("span").with_explicit_parent(None); + + let (collector, handle) = collector::mock() + .enter(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let _guard = tracing::info_span!("contextual parent").entered(); + tracing::info_span!("span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic(expected = "to be an explicit root, but was actually a contextual root")] +fn expect_explicit_root_actual_contextual_root() { + let span = expect::span().named("span").with_explicit_parent(None); + + let (collector, handle) = collector::mock().new_span(span).run_with_handle(); + + with_default(collector, || { + tracing::info_span!("span"); + }); + + handle.assert_finished(); +} + +#[test] +#[should_panic( + expected = "to be an explicit root, but actually has an explicit parent with name='explicit parent'" +)] +fn expect_explicit_root_actual_explicit_parent() { + let span = expect::span().named("span").with_explicit_parent(None); + + let (collector, handle) = collector::mock() + .new_span(expect::span()) + .new_span(span) + .run_with_handle(); + + with_default(collector, || { + let span = tracing::info_span!("explicit parent"); + tracing::info_span!(parent: span.id(), "span"); + }); + + handle.assert_finished(); +} + +#[test] +fn explicit_and_contextual_root_is_explicit() { + let span = expect::span().named("span").with_explicit_parent(None); + + let (collector, handle) = collector::mock().new_span(span).run_with_handle(); + + with_default(collector, || { + tracing::info_span!(parent: None, "span"); + }); + + handle.assert_finished(); +}