tracing_mock/subscriber.rs
1//! An implementation of the [`Subscriber`] trait to receive and validate
2//! `tracing` data.
3//!
4//! The [`MockSubscriber`] is the central component of this crate. The
5//! `MockSubscriber` has expectations set on it which are later
6//! validated as the code under test is run.
7//!
8//! # Examples
9//!
10//! ```
11//! use tracing_mock::{expect, subscriber, field};
12//!
13//! let (subscriber, handle) = subscriber::mock()
14//! // Expect a single event with a specified message
15//! .event(expect::event().with_fields(expect::msg("droids")))
16//! .only()
17//! .run_with_handle();
18//!
19//! // Use `with_default` to apply the `MockSubscriber` for the duration
20//! // of the closure - this is what we are testing.
21//! tracing::subscriber::with_default(subscriber, || {
22//! // These *are* the droids we are looking for
23//! tracing::info!("droids");
24//! });
25//!
26//! // Use the handle to check the assertions. This line will panic if an
27//! // assertion is not met.
28//! handle.assert_finished();
29//! ```
30//!
31//! A more complex example may consider multiple spans and events with
32//! their respective fields:
33//!
34//! ```
35//! use tracing_mock::{expect, subscriber, field};
36//!
37//! let span = expect::span()
38//! .named("my_span");
39//! let (subscriber, handle) = subscriber::mock()
40//! // Enter a matching span
41//! .enter(&span)
42//! // Record an event with message "subscriber parting message"
43//! .event(expect::event().with_fields(expect::msg("subscriber parting message")))
44//! // Record a value for the field `parting` on a matching span
45//! .record(&span, expect::field("parting").with_value(&"goodbye world!"))
46//! // Exit a matching span
47//! .exit(span)
48//! // Expect no further messages to be recorded
49//! .only()
50//! // Return the subscriber and handle
51//! .run_with_handle();
52//!
53//! // Use `with_default` to apply the `MockSubscriber` for the duration
54//! // of the closure - this is what we are testing.
55//! tracing::subscriber::with_default(subscriber, || {
56//! let span = tracing::trace_span!(
57//! "my_span",
58//! greeting = "hello world",
59//! parting = tracing::field::Empty
60//! );
61//!
62//! let _guard = span.enter();
63//! tracing::info!("subscriber parting message");
64//! let parting = "goodbye world!";
65//!
66//! span.record("parting", &parting);
67//! });
68//!
69//! // Use the handle to check the assertions. This line will panic if an
70//! // assertion is not met.
71//! handle.assert_finished();
72//! ```
73//!
74//! If we modify the previous example so that we **don't** enter the
75//! span before recording an event, the test will fail:
76//!
77//! ```should_panic
78//! use tracing_mock::{expect, subscriber, field};
79//!
80//! let span = expect::span()
81//! .named("my_span");
82//! let (subscriber, handle) = subscriber::mock()
83//! .enter(&span)
84//! .event(expect::event().with_fields(expect::msg("collect parting message")))
85//! .record(&span, expect::field("parting").with_value(&"goodbye world!"))
86//! .exit(span)
87//! .only()
88//! .run_with_handle();
89//!
90//! // Use `with_default` to apply the `MockSubscriber` for the duration
91//! // of the closure - this is what we are testing.
92//! tracing::subscriber::with_default(subscriber, || {
93//! let span = tracing::trace_span!(
94//! "my_span",
95//! greeting = "hello world",
96//! parting = tracing::field::Empty
97//! );
98//!
99//! // Don't enter the span.
100//! // let _guard = span.enter();
101//! tracing::info!("subscriber parting message");
102//! let parting = "goodbye world!";
103//!
104//! span.record("parting", &parting);
105//! });
106//!
107//! // Use the handle to check the assertions. This line will panic if an
108//! // assertion is not met.
109//! handle.assert_finished();
110//! ```
111//!
112//! This will result in an error message such as the following:
113//!
114//! ```text
115//! thread 'main' panicked at '
116//! [main] expected to enter a span named `my_span`
117//! [main] but instead observed event Event {
118//! fields: ValueSet {
119//! message: subscriber parting message,
120//! callsite: Identifier(0x10eda3278),
121//! },
122//! metadata: Metadata {
123//! name: "event src/subscriber.rs:27",
124//! target: "rust_out",
125//! level: Level(
126//! Info,
127//! ),
128//! module_path: "rust_out",
129//! location: src/subscriber.rs:27,
130//! fields: {message},
131//! callsite: Identifier(0x10eda3278),
132//! kind: Kind(EVENT),
133//! },
134//! parent: Current,
135//! }', tracing/tracing-mock/src/expect.rs:59:33
136//! ```
137//!
138//! [`Subscriber`]: trait@tracing::Subscriber
139//! [`MockSubscriber`]: struct@crate::subscriber::MockSubscriber
140use std::{
141 collections::{HashMap, VecDeque},
142 sync::{
143 atomic::{AtomicUsize, Ordering},
144 Arc, Mutex,
145 },
146 thread,
147};
148use tracing::{
149 level_filters::LevelFilter,
150 span::{self, Attributes, Id},
151 subscriber::Interest,
152 Event, Metadata, Subscriber,
153};
154
155use crate::{
156 ancestry::get_ancestry,
157 event::ExpectedEvent,
158 expect::Expect,
159 field::ExpectedFields,
160 span::{ActualSpan, ExpectedSpan, NewSpan},
161};
162
163pub(crate) struct SpanState {
164 id: Id,
165 name: &'static str,
166 refs: usize,
167 meta: &'static Metadata<'static>,
168}
169
170impl From<&SpanState> for ActualSpan {
171 fn from(span_state: &SpanState) -> Self {
172 Self::new(span_state.id.clone(), Some(span_state.meta))
173 }
174}
175
176struct Running<F: Fn(&Metadata<'_>) -> bool> {
177 spans: Mutex<HashMap<Id, SpanState>>,
178 expected: Arc<Mutex<VecDeque<Expect>>>,
179 current: Mutex<Vec<Id>>,
180 ids: AtomicUsize,
181 max_level: Option<LevelFilter>,
182 filter: F,
183 name: String,
184}
185
186/// A subscriber which can validate received traces.
187///
188/// For a detailed description and examples see the documentation
189/// for the methods and the [`subscriber`] module.
190///
191/// [`subscriber`]: mod@crate::subscriber
192#[derive(Debug)]
193pub struct MockSubscriber<F: Fn(&Metadata<'_>) -> bool> {
194 expected: VecDeque<Expect>,
195 max_level: Option<LevelFilter>,
196 filter: F,
197 name: String,
198}
199
200/// A handle which is used to invoke validation of expectations.
201///
202/// The handle is currently only used to assert that all the expected
203/// events and spans were seen.
204///
205/// For additional information and examples, see the [`subscriber`]
206/// module documentation.
207///
208/// [`subscriber`]: mod@crate::subscriber
209#[derive(Debug)]
210pub struct MockHandle(Arc<Mutex<VecDeque<Expect>>>, String);
211
212/// Create a new [`MockSubscriber`].
213///
214/// For additional information and examples, see the [`subscriber`]
215/// module and [`MockSubscriber`] documentation.
216///
217/// # Examples
218///
219///
220/// ```
221/// use tracing_mock::{expect, subscriber, field};
222///
223/// let span = expect::span()
224/// .named("my_span");
225/// let (subscriber, handle) = subscriber::mock()
226/// // Enter a matching span
227/// .enter(&span)
228/// // Record an event with message "subscriber parting message"
229/// .event(expect::event().with_fields(expect::msg("subscriber parting message")))
230/// // Record a value for the field `parting` on a matching span
231/// .record(&span, expect::field("parting").with_value(&"goodbye world!"))
232/// // Exit a matching span
233/// .exit(span)
234/// // Expect no further messages to be recorded
235/// .only()
236/// // Return the subscriber and handle
237/// .run_with_handle();
238///
239/// // Use `with_default` to apply the `MockSubscriber` for the duration
240/// // of the closure - this is what we are testing.
241/// tracing::subscriber::with_default(subscriber, || {
242/// let span = tracing::trace_span!(
243/// "my_span",
244/// greeting = "hello world",
245/// parting = tracing::field::Empty
246/// );
247///
248/// let _guard = span.enter();
249/// tracing::info!("subscriber parting message");
250/// let parting = "goodbye world!";
251///
252/// span.record("parting", &parting);
253/// });
254///
255/// // Use the handle to check the assertions. This line will panic if an
256/// // assertion is not met.
257/// handle.assert_finished();
258/// ```
259///
260/// [`subscriber`]: mod@crate::subscriber
261#[must_use]
262pub fn mock() -> MockSubscriber<fn(&Metadata<'_>) -> bool> {
263 MockSubscriber {
264 expected: VecDeque::new(),
265 filter: (|_: &Metadata<'_>| true) as for<'r, 's> fn(&'r Metadata<'s>) -> _,
266 max_level: None,
267 name: thread::current()
268 .name()
269 .unwrap_or("mock_subscriber")
270 .to_string(),
271 }
272}
273
274impl<F> MockSubscriber<F>
275where
276 F: Fn(&Metadata<'_>) -> bool + 'static,
277{
278 /// Overrides the name printed by the mock subscriber's debugging output.
279 ///
280 /// The debugging output is displayed if the test panics, or if the test is
281 /// run with `--nocapture`.
282 ///
283 /// By default, the mock subscriber's name is the name of the test
284 /// (*technically*, the name of the thread where it was created, which is
285 /// the name of the test unless tests are run with `--test-threads=1`).
286 /// When a test has only one mock subscriber, this is sufficient. However,
287 /// some tests may include multiple subscribers, in order to test
288 /// interactions between multiple subscribers. In that case, it can be
289 /// helpful to give each subscriber a separate name to distinguish where the
290 /// debugging output comes from.
291 ///
292 /// # Examples
293 ///
294 /// In the following example, we create 2 subscribers, both
295 /// expecting to receive an event. As we only record a single
296 /// event, the test will fail:
297 ///
298 /// ```should_panic
299 /// use tracing_mock::{expect, subscriber};
300 ///
301 /// let (subscriber_1, handle_1) = subscriber::mock()
302 /// .named("subscriber-1")
303 /// .event(expect::event())
304 /// .run_with_handle();
305 ///
306 /// let (subscriber_2, handle_2) = subscriber::mock()
307 /// .named("subscriber-2")
308 /// .event(expect::event())
309 /// .run_with_handle();
310 ///
311 /// let _guard = tracing::subscriber::set_default(subscriber_2);
312 ///
313 /// tracing::subscriber::with_default(subscriber_1, || {
314 /// tracing::info!("a");
315 /// });
316 ///
317 /// handle_1.assert_finished();
318 /// handle_2.assert_finished();
319 /// ```
320 ///
321 /// In the test output, we see that the subscriber which didn't
322 /// received the event was the one named `subscriber-2`, which is
323 /// correct as the subscriber named `subscriber-1` was the default
324 /// when the event was recorded:
325 ///
326 /// ```text
327 /// [subscriber-2] more notifications expected: [
328 /// Event(
329 /// MockEvent,
330 /// ),
331 /// ]', tracing-mock/src/subscriber.rs:1276:13
332 /// ```
333 pub fn named(self, name: impl ToString) -> Self {
334 Self {
335 name: name.to_string(),
336 ..self
337 }
338 }
339
340 /// Adds an expectation that an event matching the [`ExpectedEvent`]
341 /// will be recorded next.
342 ///
343 /// The `event` can be a default mock which will match any event
344 /// (`expect::event()`) or can include additional expectations.
345 /// See the [`ExpectedEvent`] documentation for more details.
346 ///
347 /// If an event is recorded that doesn't match the `ExpectedEvent`,
348 /// or if something else (such as entering a span) is recorded
349 /// first, then the expectation will fail.
350 ///
351 /// # Examples
352 ///
353 /// ```
354 /// use tracing_mock::{expect, subscriber};
355 ///
356 /// let (subscriber, handle) = subscriber::mock()
357 /// .event(expect::event())
358 /// .run_with_handle();
359 ///
360 /// tracing::subscriber::with_default(subscriber, || {
361 /// tracing::info!("a");
362 /// });
363 ///
364 /// handle.assert_finished();
365 /// ```
366 ///
367 /// A span is entered before the event, causing the test to fail:
368 ///
369 /// ```should_panic
370 /// use tracing_mock::{expect, subscriber};
371 ///
372 /// let (subscriber, handle) = subscriber::mock()
373 /// .event(expect::event())
374 /// .run_with_handle();
375 ///
376 /// tracing::subscriber::with_default(subscriber, || {
377 /// let span = tracing::info_span!("span");
378 /// let _guard = span.enter();
379 /// tracing::info!("a");
380 /// });
381 ///
382 /// handle.assert_finished();
383 /// ```
384 pub fn event(mut self, event: ExpectedEvent) -> Self {
385 self.expected.push_back(Expect::Event(event));
386 self
387 }
388
389 /// Adds an expectation that the creation of a span will be
390 /// recorded next.
391 ///
392 /// This function accepts `Into<NewSpan>` instead of
393 /// [`ExpectedSpan`] directly, so it can be used to test
394 /// span fields and the span parent. This is because a
395 /// subscriber only receives the span fields and parent when
396 /// a span is created, not when it is entered.
397 ///
398 /// The new span doesn't need to be entered for this expectation
399 /// to succeed.
400 ///
401 /// If a span is recorded that doesn't match the `ExpectedSpan`,
402 /// or if something else (such as an event) is recorded first,
403 /// then the expectation will fail.
404 ///
405 /// # Examples
406 ///
407 /// ```
408 /// use tracing_mock::{expect, subscriber};
409 ///
410 /// let span = expect::span()
411 /// .at_level(tracing::Level::INFO)
412 /// .named("the span we're testing")
413 /// .with_fields(expect::field("testing").with_value(&"yes"));
414 /// let (subscriber, handle) = subscriber::mock()
415 /// .new_span(span)
416 /// .run_with_handle();
417 ///
418 /// tracing::subscriber::with_default(subscriber, || {
419 /// _ = tracing::info_span!("the span we're testing", testing = "yes");
420 /// });
421 ///
422 /// handle.assert_finished();
423 /// ```
424 ///
425 /// An event is recorded before the span is created, causing the
426 /// test to fail:
427 ///
428 /// ```should_panic
429 /// use tracing_mock::{expect, subscriber};
430 ///
431 /// let span = expect::span()
432 /// .at_level(tracing::Level::INFO)
433 /// .named("the span we're testing")
434 /// .with_fields(expect::field("testing").with_value(&"yes"));
435 /// let (subscriber, handle) = subscriber::mock()
436 /// .new_span(span)
437 /// .run_with_handle();
438 ///
439 /// tracing::subscriber::with_default(subscriber, || {
440 /// tracing::info!("an event");
441 /// _ = tracing::info_span!("the span we're testing", testing = "yes");
442 /// });
443 ///
444 /// handle.assert_finished();
445 /// ```
446 pub fn new_span<I>(mut self, new_span: I) -> Self
447 where
448 I: Into<NewSpan>,
449 {
450 self.expected.push_back(Expect::NewSpan(new_span.into()));
451 self
452 }
453
454 /// Adds an expectation that entering a span matching the
455 /// [`ExpectedSpan`] will be recorded next.
456 ///
457 /// This expectation is generally accompanied by a call to
458 /// [`exit`] as well. If used together with [`only`], this
459 /// is necessary.
460 ///
461 /// If the span that is entered doesn't match the [`ExpectedSpan`],
462 /// or if something else (such as an event) is recorded first,
463 /// then the expectation will fail.
464 ///
465 /// # Examples
466 ///
467 /// ```
468 /// use tracing_mock::{expect, subscriber};
469 ///
470 /// let span = expect::span()
471 /// .at_level(tracing::Level::INFO)
472 /// .named("the span we're testing");
473 /// let (subscriber, handle) = subscriber::mock()
474 /// .enter(&span)
475 /// .exit(&span)
476 /// .only()
477 /// .run_with_handle();
478 ///
479 /// tracing::subscriber::with_default(subscriber, || {
480 /// let span = tracing::info_span!("the span we're testing");
481 /// let _entered = span.enter();
482 /// });
483 ///
484 /// handle.assert_finished();
485 /// ```
486 ///
487 /// An event is recorded before the span is entered, causing the
488 /// test to fail:
489 ///
490 /// ```should_panic
491 /// use tracing_mock::{expect, subscriber};
492 ///
493 /// let span = expect::span()
494 /// .at_level(tracing::Level::INFO)
495 /// .named("the span we're testing");
496 /// let (subscriber, handle) = subscriber::mock()
497 /// .enter(&span)
498 /// .exit(&span)
499 /// .only()
500 /// .run_with_handle();
501 ///
502 /// tracing::subscriber::with_default(subscriber, || {
503 /// tracing::info!("an event");
504 /// let span = tracing::info_span!("the span we're testing");
505 /// let _entered = span.enter();
506 /// });
507 ///
508 /// handle.assert_finished();
509 /// ```
510 ///
511 /// [`exit`]: fn@Self::exit
512 /// [`only`]: fn@Self::only
513 pub fn enter<S>(mut self, span: S) -> Self
514 where
515 S: Into<ExpectedSpan>,
516 {
517 self.expected.push_back(Expect::Enter(span.into()));
518 self
519 }
520
521 /// Adds ab expectation that exiting a span matching the
522 /// [`ExpectedSpan`] will be recorded next.
523 ///
524 /// As a span may be entered and exited multiple times,
525 /// this is different from the span being closed. In
526 /// general [`enter`] and `exit` should be paired.
527 ///
528 /// If the span that is exited doesn't match the [`ExpectedSpan`],
529 /// or if something else (such as an event) is recorded first,
530 /// then the expectation will fail.
531 ///
532 /// # Examples
533 ///
534 /// ```
535 /// use tracing_mock::{expect, subscriber};
536 ///
537 /// let span = expect::span()
538 /// .at_level(tracing::Level::INFO)
539 /// .named("the span we're testing");
540 /// let (subscriber, handle) = subscriber::mock()
541 /// .enter(&span)
542 /// .exit(&span)
543 /// .run_with_handle();
544 ///
545 /// tracing::subscriber::with_default(subscriber, || {
546 /// let span = tracing::info_span!("the span we're testing");
547 /// let _entered = span.enter();
548 /// });
549 ///
550 /// handle.assert_finished();
551 /// ```
552 ///
553 /// An event is recorded before the span is exited, causing the
554 /// test to fail:
555 ///
556 /// ```should_panic
557 /// use tracing_mock::{expect, subscriber};
558 ///
559 /// let span = expect::span()
560 /// .at_level(tracing::Level::INFO)
561 /// .named("the span we're testing");
562 /// let (subscriber, handle) = subscriber::mock()
563 /// .enter(&span)
564 /// .exit(&span)
565 /// .run_with_handle();
566 ///
567 /// tracing::subscriber::with_default(subscriber, || {
568 /// let span = tracing::info_span!("the span we're testing");
569 /// let _entered = span.enter();
570 /// tracing::info!("an event");
571 /// });
572 ///
573 /// handle.assert_finished();
574 /// ```
575 ///
576 /// [`enter`]: fn@Self::enter
577 pub fn exit<S>(mut self, span: S) -> Self
578 where
579 S: Into<ExpectedSpan>,
580 {
581 self.expected.push_back(Expect::Exit(span.into()));
582 self
583 }
584
585 /// Adds an expectation that cloning a span matching the
586 /// [`ExpectedSpan`] will be recorded next.
587 ///
588 /// The cloned span does need to be entered.
589 ///
590 /// If the span that is cloned doesn't match the [`ExpectedSpan`],
591 /// or if something else (such as an event) is recorded first,
592 /// then the expectation will fail.
593 ///
594 /// # Examples
595 ///
596 /// ```
597 /// use tracing_mock::{expect, subscriber};
598 ///
599 /// let span = expect::span()
600 /// .at_level(tracing::Level::INFO)
601 /// .named("the span we're testing");
602 /// let (subscriber, handle) = subscriber::mock()
603 /// .clone_span(span)
604 /// .run_with_handle();
605 ///
606 /// tracing::subscriber::with_default(subscriber, || {
607 /// let span = tracing::info_span!("the span we're testing");
608 /// _ = span.clone();
609 /// });
610 ///
611 /// handle.assert_finished();
612 /// ```
613 ///
614 /// An event is recorded before the span is cloned, causing the
615 /// test to fail:
616 ///
617 /// ```should_panic
618 /// use tracing_mock::{expect, subscriber};
619 ///
620 /// let span = expect::span()
621 /// .at_level(tracing::Level::INFO)
622 /// .named("the span we're testing");
623 /// let (subscriber, handle) = subscriber::mock()
624 /// .clone_span(span)
625 /// .run_with_handle();
626 ///
627 /// tracing::subscriber::with_default(subscriber, || {
628 /// let span = tracing::info_span!("the span we're testing");
629 /// tracing::info!("an event");
630 /// _ = span.clone();
631 /// });
632 ///
633 /// handle.assert_finished();
634 /// ```
635 pub fn clone_span<S>(mut self, span: S) -> Self
636 where
637 S: Into<ExpectedSpan>,
638 {
639 self.expected.push_back(Expect::CloneSpan(span.into()));
640 self
641 }
642
643 /// **This method is deprecated.**
644 ///
645 /// Adds an expectation that a span matching the [`ExpectedSpan`]
646 /// getting dropped via the deprecated function
647 /// [`Subscriber::drop_span`] will be recorded next.
648 ///
649 /// Instead [`Subscriber::try_close`] should be used on the subscriber
650 /// and should be asserted with `close_span` (which hasn't been
651 /// implemented yet, but will be done as part of #539).
652 ///
653 /// [`Subscriber::drop_span`]: fn@tracing::Subscriber::drop_span
654 #[allow(deprecated)]
655 pub fn drop_span<S>(mut self, span: S) -> Self
656 where
657 S: Into<ExpectedSpan>,
658 {
659 self.expected.push_back(Expect::DropSpan(span.into()));
660 self
661 }
662
663 /// Adds an expectation that a `follows_from` relationship will be
664 /// recorded next. Specifically that a span matching `consequence`
665 /// follows from a span matching `cause`.
666 ///
667 /// For further details on what this causal relationship means, see
668 /// [`Span::follows_from`].
669 ///
670 /// If either of the 2 spans don't match their respective
671 /// [`ExpectedSpan`] or if something else (such as an event) is
672 /// recorded first, then the expectation will fail.
673 ///
674 /// **Note**: The 2 spans, `consequence` and `cause` are matched
675 /// by `name` only.
676 ///
677 /// # Examples
678 ///
679 /// ```
680 /// use tracing_mock::{expect, subscriber};
681 ///
682 /// let cause = expect::span().named("cause");
683 /// let consequence = expect::span().named("consequence");
684 ///
685 /// let (subscriber, handle) = subscriber::mock()
686 /// .follows_from(consequence, cause)
687 /// .run_with_handle();
688 ///
689 /// tracing::subscriber::with_default(subscriber, || {
690 /// let cause = tracing::info_span!("cause");
691 /// let consequence = tracing::info_span!("consequence");
692 ///
693 /// consequence.follows_from(&cause);
694 /// });
695 ///
696 /// handle.assert_finished();
697 /// ```
698 ///
699 /// The `cause` span doesn't match, it is actually recorded at
700 /// `Level::WARN` instead of the expected `Level::INFO`, causing
701 /// this test to fail:
702 ///
703 /// ```should_panic
704 /// use tracing_mock::{expect, subscriber};
705 ///
706 /// let cause = expect::span().named("cause");
707 /// let consequence = expect::span().named("consequence");
708 ///
709 /// let (subscriber, handle) = subscriber::mock()
710 /// .follows_from(consequence, cause)
711 /// .run_with_handle();
712 ///
713 /// tracing::subscriber::with_default(subscriber, || {
714 /// let cause = tracing::info_span!("another cause");
715 /// let consequence = tracing::info_span!("consequence");
716 ///
717 /// consequence.follows_from(&cause);
718 /// });
719 ///
720 /// handle.assert_finished();
721 /// ```
722 ///
723 /// [`Span::follows_from`]: fn@tracing::Span::follows_from
724 pub fn follows_from<S1, S2>(mut self, consequence: S1, cause: S2) -> Self
725 where
726 S1: Into<ExpectedSpan>,
727 S2: Into<ExpectedSpan>,
728 {
729 self.expected.push_back(Expect::FollowsFrom {
730 consequence: consequence.into(),
731 cause: cause.into(),
732 });
733 self
734 }
735
736 /// Adds an expectation that `fields` are recorded on a span
737 /// matching the [`ExpectedSpan`] will be recorded next.
738 ///
739 /// For further information on how to specify the expected
740 /// fields, see the documentation on the [`field`] module.
741 ///
742 /// If either the span doesn't match the [`ExpectedSpan`], the
743 /// fields don't match the expected fields, or if something else
744 /// (such as an event) is recorded first, then the expectation
745 /// will fail.
746 ///
747 /// # Examples
748 ///
749 /// ```
750 /// use tracing_mock::{expect, subscriber};
751 ///
752 /// let span = expect::span()
753 /// .named("my_span");
754 /// let (subscriber, handle) = subscriber::mock()
755 /// .record(span, expect::field("parting").with_value(&"goodbye world!"))
756 /// .run_with_handle();
757 ///
758 /// tracing::subscriber::with_default(subscriber, || {
759 /// let span = tracing::trace_span!(
760 /// "my_span",
761 /// greeting = "hello world",
762 /// parting = tracing::field::Empty
763 /// );
764 /// span.record("parting", "goodbye world!");
765 /// });
766 ///
767 /// handle.assert_finished();
768 /// ```
769 ///
770 /// The value of the recorded field doesn't match the expectation,
771 /// causing the test to fail:
772 ///
773 /// ```should_panic
774 /// use tracing_mock::{expect, subscriber};
775 ///
776 /// let span = expect::span()
777 /// .named("my_span");
778 /// let (subscriber, handle) = subscriber::mock()
779 /// .record(span, expect::field("parting").with_value(&"goodbye world!"))
780 /// .run_with_handle();
781 ///
782 /// tracing::subscriber::with_default(subscriber, || {
783 /// let span = tracing::trace_span!(
784 /// "my_span",
785 /// greeting = "hello world",
786 /// parting = tracing::field::Empty
787 /// );
788 /// span.record("parting", "goodbye universe!");
789 /// });
790 ///
791 /// handle.assert_finished();
792 /// ```
793 ///
794 /// [`field`]: mod@crate::field
795 pub fn record<S, I>(mut self, span: S, fields: I) -> Self
796 where
797 S: Into<ExpectedSpan>,
798 I: Into<ExpectedFields>,
799 {
800 self.expected
801 .push_back(Expect::Visit(span.into(), fields.into()));
802 self
803 }
804
805 /// Adds an expectation that [`Subscriber::on_register_dispatch`] will
806 /// be called next.
807 ///
808 /// **Note**: This expectation is usually fulfilled automatically when
809 /// a subscriber is set as the default via [`tracing::subscriber::with_default`]
810 /// or [`tracing::subscriber::set_global_default`], so explicitly expecting
811 /// this is not usually necessary. However, it may be useful when testing
812 /// custom subscriber implementations that manually call `on_register_dispatch`.
813 ///
814 /// # Examples
815 ///
816 /// ```
817 /// use tracing_mock::{expect, subscriber};
818 ///
819 /// let (subscriber, handle) = subscriber::mock()
820 /// .on_register_dispatch()
821 /// .run_with_handle();
822 ///
823 /// tracing::subscriber::with_default(subscriber, || {
824 /// // The subscriber's on_register_dispatch was called when it was set as default
825 /// });
826 ///
827 /// handle.assert_finished();
828 /// ```
829 ///
830 ///
831 /// ```should_panic
832 /// use tracing_mock::{subscriber};
833 ///
834 /// struct WrapSubscriber<S: tracing::Subscriber> {
835 /// inner: S,
836 /// }
837 ///
838 /// impl<S: tracing::Subscriber> tracing::Subscriber for WrapSubscriber<S> {
839 /// # fn enabled(&self, metadata: &tracing::Metadata<'_>) -> bool {
840 /// # self.inner.enabled(metadata)
841 /// # }
842 /// # fn new_span(&self, span: &tracing_core::span::Attributes<'_>) -> tracing_core::span::Id {
843 /// # self.inner.new_span(span)
844 /// # }
845 /// # fn record(&self, span: &tracing_core::span::Id, values: &tracing_core::span::Record<'_>) {
846 /// # self.inner.record(span, values)
847 /// # }
848 /// # fn record_follows_from(
849 /// # &self,
850 /// # span: &tracing_core::span::Id,
851 /// # follows: &tracing_core::span::Id,
852 /// # ) {
853 /// # self.inner.record_follows_from(span, follows)
854 /// # }
855 /// # fn event(&self, event: &tracing::Event<'_>) {
856 /// # self.inner.event(event)
857 /// # }
858 /// # fn enter(&self, span: &tracing_core::span::Id) {
859 /// # self.inner.enter(span)
860 /// # }
861 /// # fn exit(&self, span: &tracing_core::span::Id) {
862 /// # self.inner.exit(span)
863 /// # }
864 /// // All other Subscriber methods implemented to forward correctly.
865 ///
866 /// fn on_register_dispatch(&self, subscriber: &tracing::Dispatch) {
867 /// // Doesn't forward to `self.inner`
868 /// let _ = subscriber;
869 /// }
870 /// }
871 ///
872 /// let (subscriber, handle) = subscriber::mock().on_register_dispatch().run_with_handle();
873 /// let wrap_subscriber = WrapSubscriber { inner: subscriber };
874 ///
875 /// tracing::subscriber::with_default(wrap_subscriber, || {
876 /// // The subscriber's on_register_dispatch is called when set as default
877 /// });
878 ///
879 /// handle.assert_finished();
880 /// ```
881 ///
882 /// [`Subscriber::on_register_dispatch`]: tracing::Subscriber::on_register_dispatch
883 pub fn on_register_dispatch(mut self) -> Self {
884 self.expected.push_back(Expect::OnRegisterDispatch);
885 self
886 }
887
888 /// Filter the traces evaluated by the `MockSubscriber`.
889 ///
890 /// The filter will be applied to all traces received before
891 /// any validation occurs - so its position in the call chain
892 /// is not important. The filter does not perform any validation
893 /// itself.
894 ///
895 /// # Examples
896 ///
897 /// ```
898 /// use tracing_mock::{expect, subscriber};
899 ///
900 /// let (subscriber, handle) = subscriber::mock()
901 /// .with_filter(|meta| meta.level() <= &tracing::Level::WARN)
902 /// .event(expect::event())
903 /// .only()
904 /// .run_with_handle();
905 ///
906 /// tracing::subscriber::with_default(subscriber, || {
907 /// tracing::info!("a");
908 /// tracing::warn!("b");
909 /// });
910 ///
911 /// handle.assert_finished();
912 /// ```
913 pub fn with_filter<G>(self, filter: G) -> MockSubscriber<G>
914 where
915 G: Fn(&Metadata<'_>) -> bool + 'static,
916 {
917 MockSubscriber {
918 expected: self.expected,
919 filter,
920 max_level: self.max_level,
921 name: self.name,
922 }
923 }
924
925 /// Sets the max level that will be provided to the `tracing`
926 /// system.
927 ///
928 /// This method can be used to test the internals of `tracing`,
929 /// but it is also useful to filter out traces on more verbose
930 /// levels if you only want to verify above a certain level.
931 ///
932 /// **Note**: this value determines a global filter, if
933 /// `with_max_level_hint` is called on multiple subscribers, the
934 /// global filter will be the least restrictive of all subscribers.
935 /// To filter the events evaluated by a specific `MockSubscriber`,
936 /// use [`with_filter`] instead.
937 ///
938 /// # Examples
939 ///
940 /// ```
941 /// use tracing_mock::{expect, subscriber};
942 ///
943 /// let (subscriber, handle) = subscriber::mock()
944 /// .with_max_level_hint(tracing::Level::INFO)
945 /// .event(expect::event().at_level(tracing::Level::INFO))
946 /// .only()
947 /// .run_with_handle();
948 ///
949 /// tracing::subscriber::with_default(subscriber, || {
950 /// tracing::debug!("a message we don't care about");
951 /// tracing::info!("a message we want to validate");
952 /// });
953 ///
954 /// handle.assert_finished();
955 /// ```
956 ///
957 /// [`with_filter`]: fn@Self::with_filter
958 pub fn with_max_level_hint(self, hint: impl Into<LevelFilter>) -> Self {
959 Self {
960 max_level: Some(hint.into()),
961 ..self
962 }
963 }
964
965 /// Expects that no further traces are received.
966 ///
967 /// The call to `only` should appear immediately before the final
968 /// call to `run` or `run_with_handle`, as any expectations which
969 /// are added after `only` will not be considered.
970 ///
971 /// # Examples
972 ///
973 /// Consider this simple test. It passes even though we only
974 /// expect a single event, but receive three:
975 ///
976 /// ```
977 /// use tracing_mock::{expect, subscriber};
978 ///
979 /// let (subscriber, handle) = subscriber::mock()
980 /// .event(expect::event())
981 /// .run_with_handle();
982 ///
983 /// tracing::subscriber::with_default(subscriber, || {
984 /// tracing::info!("a");
985 /// tracing::info!("b");
986 /// tracing::info!("c");
987 /// });
988 ///
989 /// handle.assert_finished();
990 /// ```
991 ///
992 /// After including `only`, the test will fail:
993 ///
994 /// ```should_panic
995 /// use tracing_mock::{expect, subscriber};
996 ///
997 /// let (subscriber, handle) = subscriber::mock()
998 /// .event(expect::event())
999 /// .only()
1000 /// .run_with_handle();
1001 ///
1002 /// tracing::subscriber::with_default(subscriber, || {
1003 /// tracing::info!("a");
1004 /// tracing::info!("b");
1005 /// tracing::info!("c");
1006 /// });
1007 ///
1008 /// handle.assert_finished();
1009 /// ```
1010 pub fn only(mut self) -> Self {
1011 self.expected.push_back(Expect::Nothing);
1012 self
1013 }
1014
1015 /// Consume the receiver and return an `impl` [`Subscriber`] which can
1016 /// be set as the default subscriber.
1017 ///
1018 /// This function is similar to [`run_with_handle`], but it doesn't
1019 /// return a [`MockHandle`]. This is useful if the desired
1020 /// assertions can be checked externally to the subscriber.
1021 ///
1022 /// # Examples
1023 ///
1024 /// The following test is used within the `tracing`
1025 /// codebase:
1026 ///
1027 /// ```
1028 /// use tracing_mock::subscriber;
1029 ///
1030 /// tracing::subscriber::with_default(subscriber::mock().run(), || {
1031 /// let foo1 = tracing::span!(tracing::Level::TRACE, "foo");
1032 /// let foo2 = foo1.clone();
1033 /// // Two handles that point to the same span are equal.
1034 /// assert_eq!(foo1, foo2);
1035 /// });
1036 /// ```
1037 ///
1038 /// [`Subscriber`]: tracing::Subscriber
1039 /// [`run_with_handle`]: fn@Self::run_with_handle
1040 pub fn run(self) -> impl Subscriber {
1041 let (subscriber, _) = self.run_with_handle();
1042 subscriber
1043 }
1044
1045 /// Consume the receiver and return an `impl` [`Subscriber`] which can
1046 /// be set as the default subscriber and a [`MockHandle`] which can
1047 /// be used to validate the provided expectations.
1048 ///
1049 /// # Examples
1050 ///
1051 /// ```
1052 /// use tracing_mock::{expect, subscriber};
1053 ///
1054 /// // subscriber and handle are returned from `run_with_handle()`
1055 /// let (subscriber, handle) = subscriber::mock()
1056 /// .event(expect::event())
1057 /// .run_with_handle();
1058 ///
1059 /// tracing::subscriber::with_default(subscriber, || {
1060 /// tracing::info!("a");
1061 /// });
1062 ///
1063 /// handle.assert_finished();
1064 /// ```
1065 ///
1066 /// [`Subscriber`]: tracing::Subscriber
1067 pub fn run_with_handle(self) -> (impl Subscriber, MockHandle) {
1068 let expected = Arc::new(Mutex::new(self.expected));
1069 let handle = MockHandle(expected.clone(), self.name.clone());
1070 let subscriber = Running {
1071 spans: Mutex::new(HashMap::new()),
1072 expected,
1073 current: Mutex::new(Vec::new()),
1074 ids: AtomicUsize::new(1),
1075 filter: self.filter,
1076 max_level: self.max_level,
1077 name: self.name,
1078 };
1079 (subscriber, handle)
1080 }
1081}
1082
1083impl<F> Subscriber for Running<F>
1084where
1085 F: Fn(&Metadata<'_>) -> bool + 'static,
1086{
1087 fn on_register_dispatch(&self, _subscriber: &tracing::Dispatch) {
1088 println!("[{}] on_register_dispatch", self.name);
1089 let mut expected = self.expected.lock().unwrap();
1090 if let Some(Expect::OnRegisterDispatch) = expected.front() {
1091 expected.pop_front();
1092 }
1093 }
1094
1095 fn enabled(&self, meta: &Metadata<'_>) -> bool {
1096 println!("[{}] enabled: {:#?}", self.name, meta);
1097 let enabled = (self.filter)(meta);
1098 println!("[{}] enabled -> {}", self.name, enabled);
1099 enabled
1100 }
1101
1102 fn register_callsite(&self, meta: &'static Metadata<'static>) -> Interest {
1103 println!("[{}] register_callsite: {:#?}", self.name, meta);
1104 if self.enabled(meta) {
1105 Interest::always()
1106 } else {
1107 Interest::never()
1108 }
1109 }
1110 fn max_level_hint(&self) -> Option<LevelFilter> {
1111 self.max_level
1112 }
1113
1114 fn record(&self, id: &Id, values: &span::Record<'_>) {
1115 let spans = self.spans.lock().unwrap();
1116 let mut expected = self.expected.lock().unwrap();
1117 let span = spans
1118 .get(id)
1119 .unwrap_or_else(|| panic!("[{}] no span for ID {:?}", self.name, id));
1120 println!(
1121 "[{}] record: {}; id={:?}; values={:?};",
1122 self.name, span.name, id, values
1123 );
1124 let was_expected = matches!(expected.front(), Some(Expect::Visit(_, _)));
1125 if was_expected {
1126 if let Expect::Visit(expected_span, mut expected_values) = expected.pop_front().unwrap()
1127 {
1128 if let Some(name) = expected_span.name() {
1129 assert_eq!(name, span.name);
1130 }
1131 let context = format!("span {}: ", span.name);
1132 let mut checker = expected_values.checker(&context, &self.name);
1133 values.record(&mut checker);
1134 checker.finish();
1135 }
1136 }
1137 }
1138
1139 fn event(&self, event: &Event<'_>) {
1140 let name = event.metadata().name();
1141 println!("[{}] event: {};", self.name, name);
1142 match self.expected.lock().unwrap().pop_front() {
1143 None => {}
1144 Some(Expect::Event(mut expected)) => {
1145 #[cfg(feature = "tracing-subscriber")]
1146 {
1147 if expected.scope_mut().is_some() {
1148 unimplemented!(
1149 "Expected scope for events is not supported with `MockSubscriber`."
1150 )
1151 }
1152 }
1153 let event_get_ancestry = || {
1154 get_ancestry(
1155 event,
1156 || self.lookup_current(),
1157 |span_id| {
1158 self.spans
1159 .lock()
1160 .unwrap()
1161 .get(span_id)
1162 .map(|span| span.into())
1163 },
1164 )
1165 };
1166 expected.check(event, event_get_ancestry, &self.name);
1167 }
1168 Some(ex) => ex.bad(&self.name, format_args!("observed event {:#?}", event)),
1169 }
1170 }
1171
1172 fn record_follows_from(&self, consequence_id: &Id, cause_id: &Id) {
1173 let spans = self.spans.lock().unwrap();
1174 if let Some(consequence_span) = spans.get(consequence_id) {
1175 if let Some(cause_span) = spans.get(cause_id) {
1176 println!(
1177 "[{}] record_follows_from: {} (id={:?}) follows {} (id={:?})",
1178 self.name, consequence_span.name, consequence_id, cause_span.name, cause_id,
1179 );
1180 match self.expected.lock().unwrap().pop_front() {
1181 None => {}
1182 Some(Expect::FollowsFrom {
1183 consequence: ref expected_consequence,
1184 cause: ref expected_cause,
1185 }) => {
1186 if let Some(name) = expected_consequence.name() {
1187 // TODO(hds): Write proper assertion text.
1188 assert_eq!(name, consequence_span.name);
1189 }
1190 if let Some(name) = expected_cause.name() {
1191 // TODO(hds): Write proper assertion text.
1192 assert_eq!(name, cause_span.name);
1193 }
1194 }
1195 Some(ex) => ex.bad(
1196 &self.name,
1197 format_args!(
1198 "consequence {:?} followed cause {:?}",
1199 consequence_span.name, cause_span.name
1200 ),
1201 ),
1202 }
1203 }
1204 };
1205 }
1206
1207 fn new_span(&self, span: &Attributes<'_>) -> Id {
1208 let meta = span.metadata();
1209 let id = self.ids.fetch_add(1, Ordering::SeqCst);
1210 let id = Id::from_u64(id as u64);
1211 println!(
1212 "[{}] new_span: name={:?}; target={:?}; id={:?};",
1213 self.name,
1214 meta.name(),
1215 meta.target(),
1216 id
1217 );
1218 let mut expected = self.expected.lock().unwrap();
1219 let was_expected = matches!(expected.front(), Some(Expect::NewSpan(_)));
1220 let mut spans = self.spans.lock().unwrap();
1221 if was_expected {
1222 if let Expect::NewSpan(mut expected) = expected.pop_front().unwrap() {
1223 if let Some(expected_id) = &expected.span.id {
1224 expected_id.set(id.into_u64()).unwrap();
1225 }
1226
1227 expected.check(
1228 span,
1229 || {
1230 get_ancestry(
1231 span,
1232 || self.lookup_current(),
1233 |span_id| spans.get(span_id).map(|span| span.into()),
1234 )
1235 },
1236 &self.name,
1237 );
1238 }
1239 }
1240 spans.insert(
1241 id.clone(),
1242 SpanState {
1243 id: id.clone(),
1244 name: meta.name(),
1245 refs: 1,
1246 meta,
1247 },
1248 );
1249 id
1250 }
1251
1252 fn enter(&self, id: &Id) {
1253 let spans = self.spans.lock().unwrap();
1254 if let Some(span) = spans.get(id) {
1255 println!("[{}] enter: {}; id={:?};", self.name, span.name, id);
1256 match self.expected.lock().unwrap().pop_front() {
1257 None => {}
1258 Some(Expect::Enter(ref expected_span)) => {
1259 expected_span.check(&span.into(), "to enter a span", &self.name);
1260 }
1261 Some(ex) => ex.bad(&self.name, format_args!("entered span {:?}", span.name)),
1262 }
1263 };
1264 self.current.lock().unwrap().push(id.clone());
1265 }
1266
1267 fn exit(&self, id: &Id) {
1268 if std::thread::panicking() {
1269 // `exit()` can be called in `drop` impls, so we must guard against
1270 // double panics.
1271 println!("[{}] exit {:?} while panicking", self.name, id);
1272 return;
1273 }
1274 let spans = self.spans.lock().unwrap();
1275 let span = spans
1276 .get(id)
1277 .unwrap_or_else(|| panic!("[{}] no span for ID {:?}", self.name, id));
1278 println!("[{}] exit: {}; id={:?};", self.name, span.name, id);
1279 match self.expected.lock().unwrap().pop_front() {
1280 None => {}
1281 Some(Expect::Exit(ref expected_span)) => {
1282 expected_span.check(&span.into(), "to exit a span", &self.name);
1283 let curr = self.current.lock().unwrap().pop();
1284 assert_eq!(
1285 Some(id),
1286 curr.as_ref(),
1287 "[{}] exited span {:?}, but the current span was {:?}",
1288 self.name,
1289 span.name,
1290 curr.as_ref().and_then(|id| spans.get(id)).map(|s| s.name)
1291 );
1292 }
1293 Some(ex) => ex.bad(&self.name, format_args!("exited span {:?}", span.name)),
1294 };
1295 }
1296
1297 fn clone_span(&self, id: &Id) -> Id {
1298 let mut spans = self.spans.lock().unwrap();
1299 let mut span = spans.get_mut(id);
1300 match span.as_deref_mut() {
1301 Some(span) => {
1302 println!(
1303 "[{}] clone_span: {}; id={:?}; refs={:?};",
1304 self.name, span.name, id, span.refs,
1305 );
1306 span.refs += 1;
1307 }
1308 None => {
1309 println!(
1310 "[{}] clone_span: id={:?} (not found in span list);",
1311 self.name, id
1312 );
1313 }
1314 }
1315
1316 let mut expected = self.expected.lock().unwrap();
1317 let was_expected = if let Some(Expect::CloneSpan(ref expected_span)) = expected.front() {
1318 match span {
1319 Some(actual_span) => {
1320 let actual_span: &_ = actual_span;
1321 expected_span.check(&actual_span.into(), "to clone a span", &self.name);
1322 }
1323 // Check only by Id
1324 None => expected_span.check(&id.into(), "to clone a span", &self.name),
1325 }
1326 true
1327 } else {
1328 false
1329 };
1330 if was_expected {
1331 expected.pop_front();
1332 }
1333 id.clone()
1334 }
1335
1336 fn drop_span(&self, id: Id) {
1337 let mut is_event = false;
1338 let name = if let Ok(mut spans) = self.spans.try_lock() {
1339 spans.get_mut(&id).map(|span| {
1340 let name = span.name;
1341 if name.contains("event") {
1342 is_event = true;
1343 }
1344 println!(
1345 "[{}] drop_span: {}; id={:?}; refs={:?};",
1346 self.name, name, id, span.refs
1347 );
1348 span.refs -= 1;
1349 name
1350 })
1351 } else {
1352 None
1353 };
1354 if name.is_none() {
1355 println!("[{}] drop_span: id={:?}", self.name, id);
1356 }
1357 if let Ok(mut expected) = self.expected.try_lock() {
1358 let was_expected = match expected.front() {
1359 Some(Expect::DropSpan(ref span)) => {
1360 // Don't assert if this function was called while panicking,
1361 // as failing the assertion can cause a double panic.
1362 if !::std::thread::panicking() {
1363 assert_eq!(name, span.name());
1364 }
1365 true
1366 }
1367 Some(Expect::Event(_)) => {
1368 if !::std::thread::panicking() {
1369 assert!(is_event, "[{}] expected an event", self.name);
1370 }
1371 true
1372 }
1373 _ => false,
1374 };
1375 if was_expected {
1376 expected.pop_front();
1377 }
1378 }
1379 }
1380
1381 fn current_span(&self) -> tracing_core::span::Current {
1382 let stack = self.current.lock().unwrap();
1383 match stack.last() {
1384 Some(id) => {
1385 let spans = self.spans.lock().unwrap();
1386 let state = spans.get(id).expect("state for current span");
1387 tracing_core::span::Current::new(id.clone(), state.meta)
1388 }
1389 None => tracing_core::span::Current::none(),
1390 }
1391 }
1392}
1393
1394impl<F> Running<F>
1395where
1396 F: Fn(&Metadata<'_>) -> bool,
1397{
1398 fn lookup_current(&self) -> Option<span::Id> {
1399 let stack = self.current.lock().unwrap();
1400 stack.last().cloned()
1401 }
1402}
1403
1404impl MockHandle {
1405 #[cfg(feature = "tracing-subscriber")]
1406 pub(crate) fn new(expected: Arc<Mutex<VecDeque<Expect>>>, name: String) -> Self {
1407 Self(expected, name)
1408 }
1409
1410 /// Checks the expectations which were set on the
1411 /// [`MockSubscriber`].
1412 ///
1413 /// Calling `assert_finished` is usually the final part of a test.
1414 ///
1415 /// # Panics
1416 ///
1417 /// This method will panic if any of the provided expectations are
1418 /// not met.
1419 ///
1420 /// # Examples
1421 ///
1422 /// ```
1423 /// use tracing_mock::{expect, subscriber};
1424 ///
1425 /// let (subscriber, handle) = subscriber::mock()
1426 /// .event(expect::event())
1427 /// .run_with_handle();
1428 ///
1429 /// tracing::subscriber::with_default(subscriber, || {
1430 /// tracing::info!("a");
1431 /// });
1432 ///
1433 /// // Check assertions set on the mock subscriber
1434 /// handle.assert_finished();
1435 /// ```
1436 pub fn assert_finished(&self) {
1437 if let Ok(ref expected) = self.0.lock() {
1438 assert!(
1439 !expected.iter().any(|thing| thing != &Expect::Nothing),
1440 "\n[{}] more notifications expected: {:#?}",
1441 self.1,
1442 **expected
1443 );
1444 }
1445 }
1446}