1use tracing_core::{
6 span::{self, Attributes},
7 Event,
8};
9
10use crate::span::{ActualSpan, ExpectedSpan};
11
12#[derive(Debug, Eq, PartialEq)]
18pub enum ExpectedAncestry {
19 HasExplicitParent(ExpectedSpan),
21 IsExplicitRoot,
24 HasContextualParent(ExpectedSpan),
28 IsContextualRoot,
32}
33
34pub(crate) enum ActualAncestry {
35 HasExplicitParent(ActualSpan),
36 IsExplicitRoot,
37 HasContextualParent(ActualSpan),
38 IsContextualRoot,
39}
40
41impl ExpectedAncestry {
42 #[track_caller]
43 pub(crate) fn check(
44 &self,
45 actual_ancestry: &ActualAncestry,
46 ctx: impl std::fmt::Display,
47 collector_name: &str,
48 ) {
49 match (self, actual_ancestry) {
50 (Self::IsExplicitRoot, ActualAncestry::IsExplicitRoot) => {}
51 (Self::IsContextualRoot, ActualAncestry::IsContextualRoot) => {}
52 (
53 Self::HasExplicitParent(expected_parent),
54 ActualAncestry::HasExplicitParent(actual_parent),
55 ) => {
56 expected_parent.check(
57 actual_parent,
58 format_args!("{ctx} to have an explicit parent span"),
59 collector_name,
60 );
61 }
62 (
63 Self::HasContextualParent(expected_parent),
64 ActualAncestry::HasContextualParent(actual_parent),
65 ) => {
66 println!("----> [{collector_name}] check {expected_parent:?} against actual parent with Id={id:?}", id = actual_parent.id());
67 expected_parent.check(
68 actual_parent,
69 format_args!("{ctx} to have a contextual parent span"),
70 collector_name,
71 );
72 }
73 _ => {
74 let expected_description = match self {
76 Self::IsExplicitRoot => "be an explicit root",
77 Self::HasExplicitParent(_) => "have an explicit parent span",
78 Self::IsContextualRoot => "be a contextual root",
79 Self::HasContextualParent(_) => "have a contextual parent span",
80 };
81
82 let actual_description = match actual_ancestry {
83 ActualAncestry::IsExplicitRoot => "is actually an explicit root",
84 ActualAncestry::HasExplicitParent(_) => "actually has an explicit parent span",
85 ActualAncestry::IsContextualRoot => "is actually a contextual root",
86 ActualAncestry::HasContextualParent(_) => {
87 "actually has a contextual parent span"
88 }
89 };
90
91 panic!(
92 "{}",
93 format!(
94 "[{collector_name}] expected {ctx} to {expected_description}, \
95 but it {actual_description}"
96 )
97 );
98 }
99 }
100 }
101}
102
103pub(crate) trait HasAncestry {
104 fn is_contextual(&self) -> bool;
105
106 fn is_root(&self) -> bool;
107
108 fn parent(&self) -> Option<&span::Id>;
109}
110
111impl HasAncestry for &Event<'_> {
112 fn is_contextual(&self) -> bool {
113 (self as &Event<'_>).is_contextual()
114 }
115
116 fn is_root(&self) -> bool {
117 (self as &Event<'_>).is_root()
118 }
119
120 fn parent(&self) -> Option<&span::Id> {
121 (self as &Event<'_>).parent()
122 }
123}
124
125impl HasAncestry for &Attributes<'_> {
126 fn is_contextual(&self) -> bool {
127 (self as &Attributes<'_>).is_contextual()
128 }
129
130 fn is_root(&self) -> bool {
131 (self as &Attributes<'_>).is_root()
132 }
133
134 fn parent(&self) -> Option<&span::Id> {
135 (self as &Attributes<'_>).parent()
136 }
137}
138
139pub(crate) fn get_ancestry(
152 item: impl HasAncestry,
153 lookup_current: impl FnOnce() -> Option<span::Id>,
154 actual_span: impl FnOnce(&span::Id) -> Option<ActualSpan>,
155) -> ActualAncestry {
156 if item.is_contextual() {
157 if let Some(parent_id) = lookup_current() {
158 let contextual_parent_span = actual_span(&parent_id).expect(
159 "tracing-mock: contextual parent cannot \
160 be looked up by ID. Was it recorded correctly?",
161 );
162 ActualAncestry::HasContextualParent(contextual_parent_span)
163 } else {
164 ActualAncestry::IsContextualRoot
165 }
166 } else if item.is_root() {
167 ActualAncestry::IsExplicitRoot
168 } else {
169 let parent_id = item.parent().expect(
170 "tracing-mock: is_contextual=false is_root=false \
171 but no explicit parent found. This is a bug!",
172 );
173 let explicit_parent_span = actual_span(parent_id).expect(
174 "tracing-mock: explicit parent cannot be looked \
175 up by ID. Is the provided Span ID valid: {parent_id}",
176 );
177 ActualAncestry::HasExplicitParent(explicit_parent_span)
178 }
179}