1 #![allow(missing_docs, dead_code)] 2 pub use tracing_mock::{event, field, span, subscriber}; 3 4 use tracing_core::{ 5 span::{Attributes, Id, Record}, 6 Event, Subscriber, 7 }; 8 use tracing_mock::{ 9 event::MockEvent, 10 span::{MockSpan, NewSpan}, 11 subscriber::{Expect, MockHandle}, 12 }; 13 use tracing_subscriber::{ 14 layer::{Context, Layer}, 15 registry::{LookupSpan, SpanRef}, 16 }; 17 18 use std::{ 19 collections::VecDeque, 20 fmt, 21 sync::{Arc, Mutex}, 22 }; 23 24 pub mod layer { 25 use super::ExpectLayerBuilder; 26 mock() -> ExpectLayerBuilder27 pub fn mock() -> ExpectLayerBuilder { 28 ExpectLayerBuilder { 29 expected: Default::default(), 30 name: std::thread::current() 31 .name() 32 .map(String::from) 33 .unwrap_or_default(), 34 } 35 } 36 named(name: impl std::fmt::Display) -> ExpectLayerBuilder37 pub fn named(name: impl std::fmt::Display) -> ExpectLayerBuilder { 38 mock().named(name) 39 } 40 } 41 42 pub struct ExpectLayerBuilder { 43 expected: VecDeque<Expect>, 44 name: String, 45 } 46 47 pub struct ExpectLayer { 48 expected: Arc<Mutex<VecDeque<Expect>>>, 49 current: Mutex<Vec<Id>>, 50 name: String, 51 } 52 53 impl ExpectLayerBuilder { 54 /// Overrides the name printed by the mock subscriber's debugging output. 55 /// 56 /// The debugging output is displayed if the test panics, or if the test is 57 /// run with `--nocapture`. 58 /// 59 /// By default, the mock subscriber's name is the name of the test 60 /// (*technically*, the name of the thread where it was created, which is 61 /// the name of the test unless tests are run with `--test-threads=1`). 62 /// When a test has only one mock subscriber, this is sufficient. However, 63 /// some tests may include multiple subscribers, in order to test 64 /// interactions between multiple subscribers. In that case, it can be 65 /// helpful to give each subscriber a separate name to distinguish where the 66 /// debugging output comes from. named(mut self, name: impl fmt::Display) -> Self67 pub fn named(mut self, name: impl fmt::Display) -> Self { 68 use std::fmt::Write; 69 if !self.name.is_empty() { 70 write!(&mut self.name, "::{}", name).unwrap(); 71 } else { 72 self.name = name.to_string(); 73 } 74 self 75 } 76 enter(mut self, span: MockSpan) -> Self77 pub fn enter(mut self, span: MockSpan) -> Self { 78 self.expected.push_back(Expect::Enter(span)); 79 self 80 } 81 event(mut self, event: MockEvent) -> Self82 pub fn event(mut self, event: MockEvent) -> Self { 83 self.expected.push_back(Expect::Event(event)); 84 self 85 } 86 exit(mut self, span: MockSpan) -> Self87 pub fn exit(mut self, span: MockSpan) -> Self { 88 self.expected.push_back(Expect::Exit(span)); 89 self 90 } 91 done(mut self) -> Self92 pub fn done(mut self) -> Self { 93 self.expected.push_back(Expect::Nothing); 94 self 95 } 96 record<I>(mut self, span: MockSpan, fields: I) -> Self where I: Into<field::Expect>,97 pub fn record<I>(mut self, span: MockSpan, fields: I) -> Self 98 where 99 I: Into<field::Expect>, 100 { 101 self.expected.push_back(Expect::Visit(span, fields.into())); 102 self 103 } 104 new_span<I>(mut self, new_span: I) -> Self where I: Into<NewSpan>,105 pub fn new_span<I>(mut self, new_span: I) -> Self 106 where 107 I: Into<NewSpan>, 108 { 109 self.expected.push_back(Expect::NewSpan(new_span.into())); 110 self 111 } 112 run(self) -> ExpectLayer113 pub fn run(self) -> ExpectLayer { 114 ExpectLayer { 115 expected: Arc::new(Mutex::new(self.expected)), 116 name: self.name, 117 current: Mutex::new(Vec::new()), 118 } 119 } 120 run_with_handle(self) -> (ExpectLayer, MockHandle)121 pub fn run_with_handle(self) -> (ExpectLayer, MockHandle) { 122 let expected = Arc::new(Mutex::new(self.expected)); 123 let handle = MockHandle::new(expected.clone(), self.name.clone()); 124 let layer = ExpectLayer { 125 expected, 126 name: self.name, 127 current: Mutex::new(Vec::new()), 128 }; 129 (layer, handle) 130 } 131 } 132 133 impl ExpectLayer { check_span_ref<'spans, S>( &self, expected: &MockSpan, actual: &SpanRef<'spans, S>, what_happened: impl fmt::Display, ) where S: LookupSpan<'spans>,134 fn check_span_ref<'spans, S>( 135 &self, 136 expected: &MockSpan, 137 actual: &SpanRef<'spans, S>, 138 what_happened: impl fmt::Display, 139 ) where 140 S: LookupSpan<'spans>, 141 { 142 if let Some(exp_name) = expected.name() { 143 assert_eq!( 144 actual.name(), 145 exp_name, 146 "\n[{}] expected {} a span named {:?}\n\ 147 [{}] but it was named {:?} instead (span {} {:?})", 148 self.name, 149 what_happened, 150 exp_name, 151 self.name, 152 actual.name(), 153 actual.name(), 154 actual.id() 155 ); 156 } 157 158 if let Some(exp_level) = expected.level() { 159 let actual_level = actual.metadata().level(); 160 assert_eq!( 161 actual_level, 162 &exp_level, 163 "\n[{}] expected {} a span at {:?}\n\ 164 [{}] but it was at {:?} instead (span {} {:?})", 165 self.name, 166 what_happened, 167 exp_level, 168 self.name, 169 actual_level, 170 actual.name(), 171 actual.id(), 172 ); 173 } 174 175 if let Some(exp_target) = expected.target() { 176 let actual_target = actual.metadata().target(); 177 assert_eq!( 178 actual_target, 179 exp_target, 180 "\n[{}] expected {} a span with target {:?}\n\ 181 [{}] but it had the target {:?} instead (span {} {:?})", 182 self.name, 183 what_happened, 184 exp_target, 185 self.name, 186 actual_target, 187 actual.name(), 188 actual.id(), 189 ); 190 } 191 } 192 } 193 194 impl<S> Layer<S> for ExpectLayer 195 where 196 S: Subscriber + for<'a> LookupSpan<'a>, 197 { register_callsite( &self, metadata: &'static tracing::Metadata<'static>, ) -> tracing_core::Interest198 fn register_callsite( 199 &self, 200 metadata: &'static tracing::Metadata<'static>, 201 ) -> tracing_core::Interest { 202 println!("[{}] register_callsite {:#?}", self.name, metadata); 203 tracing_core::Interest::always() 204 } 205 on_record(&self, _: &Id, _: &Record<'_>, _: Context<'_, S>)206 fn on_record(&self, _: &Id, _: &Record<'_>, _: Context<'_, S>) { 207 unimplemented!( 208 "so far, we don't have any tests that need an `on_record` \ 209 implementation.\nif you just wrote one that does, feel free to \ 210 implement it!" 211 ); 212 } 213 on_event(&self, event: &Event<'_>, cx: Context<'_, S>)214 fn on_event(&self, event: &Event<'_>, cx: Context<'_, S>) { 215 let name = event.metadata().name(); 216 println!( 217 "[{}] event: {}; level: {}; target: {}", 218 self.name, 219 name, 220 event.metadata().level(), 221 event.metadata().target(), 222 ); 223 match self.expected.lock().unwrap().pop_front() { 224 None => {} 225 Some(Expect::Event(mut expected)) => { 226 let get_parent_name = || cx.event_span(event).map(|span| span.name().to_string()); 227 expected.check(event, get_parent_name, &self.name); 228 let mut current_scope = cx.event_scope(event).into_iter().flatten(); 229 let expected_scope = expected.scope_mut(); 230 let mut i = 0; 231 for (expected, actual) in expected_scope.iter_mut().zip(&mut current_scope) { 232 println!( 233 "[{}] event_scope[{}] actual={} ({:?}); expected={}", 234 self.name, 235 i, 236 actual.name(), 237 actual.id(), 238 expected 239 ); 240 self.check_span_ref( 241 expected, 242 &actual, 243 format_args!("the {}th span in the event's scope to be", i), 244 ); 245 i += 1; 246 } 247 let remaining_expected = &expected_scope[i..]; 248 assert!( 249 remaining_expected.is_empty(), 250 "\n[{}] did not observe all expected spans in event scope!\n[{}] missing: {:#?}", 251 self.name, 252 self.name, 253 remaining_expected, 254 ); 255 assert!( 256 current_scope.next().is_none(), 257 "\n[{}] did not expect all spans in the actual event scope!", 258 self.name, 259 ); 260 } 261 Some(ex) => ex.bad(&self.name, format_args!("observed event {:#?}", event)), 262 } 263 } 264 on_follows_from(&self, _span: &Id, _follows: &Id, _: Context<'_, S>)265 fn on_follows_from(&self, _span: &Id, _follows: &Id, _: Context<'_, S>) { 266 // TODO: it should be possible to expect spans to follow from other spans 267 } 268 on_new_span(&self, span: &Attributes<'_>, id: &Id, cx: Context<'_, S>)269 fn on_new_span(&self, span: &Attributes<'_>, id: &Id, cx: Context<'_, S>) { 270 let meta = span.metadata(); 271 println!( 272 "[{}] new_span: name={:?}; target={:?}; id={:?};", 273 self.name, 274 meta.name(), 275 meta.target(), 276 id 277 ); 278 let mut expected = self.expected.lock().unwrap(); 279 let was_expected = matches!(expected.front(), Some(Expect::NewSpan(_))); 280 if was_expected { 281 if let Expect::NewSpan(mut expected) = expected.pop_front().unwrap() { 282 let get_parent_name = || { 283 span.parent() 284 .and_then(|id| cx.span(id)) 285 .or_else(|| cx.lookup_current()) 286 .map(|span| span.name().to_string()) 287 }; 288 expected.check(span, get_parent_name, &self.name); 289 } 290 } 291 } 292 on_enter(&self, id: &Id, cx: Context<'_, S>)293 fn on_enter(&self, id: &Id, cx: Context<'_, S>) { 294 let span = cx 295 .span(id) 296 .unwrap_or_else(|| panic!("[{}] no span for ID {:?}", self.name, id)); 297 println!("[{}] enter: {}; id={:?};", self.name, span.name(), id); 298 match self.expected.lock().unwrap().pop_front() { 299 None => {} 300 Some(Expect::Enter(ref expected_span)) => { 301 self.check_span_ref(expected_span, &span, "to enter"); 302 } 303 Some(ex) => ex.bad(&self.name, format_args!("entered span {:?}", span.name())), 304 } 305 self.current.lock().unwrap().push(id.clone()); 306 } 307 on_exit(&self, id: &Id, cx: Context<'_, S>)308 fn on_exit(&self, id: &Id, cx: Context<'_, S>) { 309 if std::thread::panicking() { 310 // `exit()` can be called in `drop` impls, so we must guard against 311 // double panics. 312 println!("[{}] exit {:?} while panicking", self.name, id); 313 return; 314 } 315 let span = cx 316 .span(id) 317 .unwrap_or_else(|| panic!("[{}] no span for ID {:?}", self.name, id)); 318 println!("[{}] exit: {}; id={:?};", self.name, span.name(), id); 319 match self.expected.lock().unwrap().pop_front() { 320 None => {} 321 Some(Expect::Exit(ref expected_span)) => { 322 self.check_span_ref(expected_span, &span, "to exit"); 323 let curr = self.current.lock().unwrap().pop(); 324 assert_eq!( 325 Some(id), 326 curr.as_ref(), 327 "[{}] exited span {:?}, but the current span was {:?}", 328 self.name, 329 span.name(), 330 curr.as_ref().and_then(|id| cx.span(id)).map(|s| s.name()) 331 ); 332 } 333 Some(ex) => ex.bad(&self.name, format_args!("exited span {:?}", span.name())), 334 }; 335 } 336 on_close(&self, id: Id, cx: Context<'_, S>)337 fn on_close(&self, id: Id, cx: Context<'_, S>) { 338 if std::thread::panicking() { 339 // `try_close` can be called in `drop` impls, so we must guard against 340 // double panics. 341 println!("[{}] close {:?} while panicking", self.name, id); 342 return; 343 } 344 let span = cx.span(&id); 345 let name = span.as_ref().map(|span| { 346 println!("[{}] close_span: {}; id={:?};", self.name, span.name(), id,); 347 span.name() 348 }); 349 if name.is_none() { 350 println!("[{}] drop_span: id={:?}", self.name, id); 351 } 352 if let Ok(mut expected) = self.expected.try_lock() { 353 let was_expected = match expected.front() { 354 Some(Expect::DropSpan(ref expected_span)) => { 355 // Don't assert if this function was called while panicking, 356 // as failing the assertion can cause a double panic. 357 if !::std::thread::panicking() { 358 if let Some(ref span) = span { 359 self.check_span_ref(expected_span, span, "to close"); 360 } 361 } 362 true 363 } 364 Some(Expect::Event(_)) => { 365 if !::std::thread::panicking() { 366 panic!( 367 "[{}] expected an event, but dropped span {} (id={:?}) instead", 368 self.name, 369 name.unwrap_or("<unknown name>"), 370 id 371 ); 372 } 373 true 374 } 375 _ => false, 376 }; 377 if was_expected { 378 expected.pop_front(); 379 } 380 } 381 } 382 on_id_change(&self, _old: &Id, _new: &Id, _ctx: Context<'_, S>)383 fn on_id_change(&self, _old: &Id, _new: &Id, _ctx: Context<'_, S>) { 384 panic!("well-behaved subscribers should never do this to us, lol"); 385 } 386 } 387 388 impl fmt::Debug for ExpectLayer { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result389 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 390 let mut s = f.debug_struct("ExpectLayer"); 391 s.field("name", &self.name); 392 393 if let Ok(expected) = self.expected.try_lock() { 394 s.field("expected", &expected); 395 } else { 396 s.field("expected", &format_args!("<locked>")); 397 } 398 399 if let Ok(current) = self.current.try_lock() { 400 s.field("current", &format_args!("{:?}", ¤t)); 401 } else { 402 s.field("current", &format_args!("<locked>")); 403 } 404 405 s.finish() 406 } 407 } 408