summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-subscriber/tests/support.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tracing-subscriber/tests/support.rs')
-rw-r--r--vendor/tracing-subscriber/tests/support.rs407
1 files changed, 407 insertions, 0 deletions
diff --git a/vendor/tracing-subscriber/tests/support.rs b/vendor/tracing-subscriber/tests/support.rs
new file mode 100644
index 000000000..50e0e6669
--- /dev/null
+++ b/vendor/tracing-subscriber/tests/support.rs
@@ -0,0 +1,407 @@
+#![allow(missing_docs, dead_code)]
+pub use tracing_mock::{event, field, span, subscriber};
+
+use tracing_core::{
+ span::{Attributes, Id, Record},
+ Event, Subscriber,
+};
+use tracing_mock::{
+ event::MockEvent,
+ span::{MockSpan, NewSpan},
+ subscriber::{Expect, MockHandle},
+};
+use tracing_subscriber::{
+ layer::{Context, Layer},
+ registry::{LookupSpan, SpanRef},
+};
+
+use std::{
+ collections::VecDeque,
+ fmt,
+ sync::{Arc, Mutex},
+};
+
+pub mod layer {
+ use super::ExpectLayerBuilder;
+
+ pub fn mock() -> ExpectLayerBuilder {
+ ExpectLayerBuilder {
+ expected: Default::default(),
+ name: std::thread::current()
+ .name()
+ .map(String::from)
+ .unwrap_or_default(),
+ }
+ }
+
+ pub fn named(name: impl std::fmt::Display) -> ExpectLayerBuilder {
+ mock().named(name)
+ }
+}
+
+pub struct ExpectLayerBuilder {
+ expected: VecDeque<Expect>,
+ name: String,
+}
+
+pub struct ExpectLayer {
+ expected: Arc<Mutex<VecDeque<Expect>>>,
+ current: Mutex<Vec<Id>>,
+ name: String,
+}
+
+impl ExpectLayerBuilder {
+ /// Overrides the name printed by the mock subscriber's debugging output.
+ ///
+ /// The debugging output is displayed if the test panics, or if the test is
+ /// run with `--nocapture`.
+ ///
+ /// By default, the mock subscriber's name is the name of the test
+ /// (*technically*, the name of the thread where it was created, which is
+ /// the name of the test unless tests are run with `--test-threads=1`).
+ /// When a test has only one mock subscriber, this is sufficient. However,
+ /// some tests may include multiple subscribers, in order to test
+ /// interactions between multiple subscribers. In that case, it can be
+ /// helpful to give each subscriber a separate name to distinguish where the
+ /// debugging output comes from.
+ pub fn named(mut self, name: impl fmt::Display) -> Self {
+ use std::fmt::Write;
+ if !self.name.is_empty() {
+ write!(&mut self.name, "::{}", name).unwrap();
+ } else {
+ self.name = name.to_string();
+ }
+ self
+ }
+
+ pub fn enter(mut self, span: MockSpan) -> Self {
+ self.expected.push_back(Expect::Enter(span));
+ self
+ }
+
+ pub fn event(mut self, event: MockEvent) -> Self {
+ self.expected.push_back(Expect::Event(event));
+ self
+ }
+
+ pub fn exit(mut self, span: MockSpan) -> Self {
+ self.expected.push_back(Expect::Exit(span));
+ self
+ }
+
+ pub fn done(mut self) -> Self {
+ self.expected.push_back(Expect::Nothing);
+ self
+ }
+
+ pub fn record<I>(mut self, span: MockSpan, fields: I) -> Self
+ where
+ I: Into<field::Expect>,
+ {
+ self.expected.push_back(Expect::Visit(span, fields.into()));
+ self
+ }
+
+ pub fn new_span<I>(mut self, new_span: I) -> Self
+ where
+ I: Into<NewSpan>,
+ {
+ self.expected.push_back(Expect::NewSpan(new_span.into()));
+ self
+ }
+
+ pub fn run(self) -> ExpectLayer {
+ ExpectLayer {
+ expected: Arc::new(Mutex::new(self.expected)),
+ name: self.name,
+ current: Mutex::new(Vec::new()),
+ }
+ }
+
+ pub fn run_with_handle(self) -> (ExpectLayer, MockHandle) {
+ let expected = Arc::new(Mutex::new(self.expected));
+ let handle = MockHandle::new(expected.clone(), self.name.clone());
+ let layer = ExpectLayer {
+ expected,
+ name: self.name,
+ current: Mutex::new(Vec::new()),
+ };
+ (layer, handle)
+ }
+}
+
+impl ExpectLayer {
+ fn check_span_ref<'spans, S>(
+ &self,
+ expected: &MockSpan,
+ actual: &SpanRef<'spans, S>,
+ what_happened: impl fmt::Display,
+ ) where
+ S: LookupSpan<'spans>,
+ {
+ if let Some(exp_name) = expected.name() {
+ assert_eq!(
+ actual.name(),
+ exp_name,
+ "\n[{}] expected {} a span named {:?}\n\
+ [{}] but it was named {:?} instead (span {} {:?})",
+ self.name,
+ what_happened,
+ exp_name,
+ self.name,
+ actual.name(),
+ actual.name(),
+ actual.id()
+ );
+ }
+
+ if let Some(exp_level) = expected.level() {
+ let actual_level = actual.metadata().level();
+ assert_eq!(
+ actual_level,
+ &exp_level,
+ "\n[{}] expected {} a span at {:?}\n\
+ [{}] but it was at {:?} instead (span {} {:?})",
+ self.name,
+ what_happened,
+ exp_level,
+ self.name,
+ actual_level,
+ actual.name(),
+ actual.id(),
+ );
+ }
+
+ if let Some(exp_target) = expected.target() {
+ let actual_target = actual.metadata().target();
+ assert_eq!(
+ actual_target,
+ exp_target,
+ "\n[{}] expected {} a span with target {:?}\n\
+ [{}] but it had the target {:?} instead (span {} {:?})",
+ self.name,
+ what_happened,
+ exp_target,
+ self.name,
+ actual_target,
+ actual.name(),
+ actual.id(),
+ );
+ }
+ }
+}
+
+impl<S> Layer<S> for ExpectLayer
+where
+ S: Subscriber + for<'a> LookupSpan<'a>,
+{
+ fn register_callsite(
+ &self,
+ metadata: &'static tracing::Metadata<'static>,
+ ) -> tracing_core::Interest {
+ println!("[{}] register_callsite {:#?}", self.name, metadata);
+ tracing_core::Interest::always()
+ }
+
+ fn on_record(&self, _: &Id, _: &Record<'_>, _: Context<'_, S>) {
+ unimplemented!(
+ "so far, we don't have any tests that need an `on_record` \
+ implementation.\nif you just wrote one that does, feel free to \
+ implement it!"
+ );
+ }
+
+ fn on_event(&self, event: &Event<'_>, cx: Context<'_, S>) {
+ let name = event.metadata().name();
+ println!(
+ "[{}] event: {}; level: {}; target: {}",
+ self.name,
+ name,
+ event.metadata().level(),
+ event.metadata().target(),
+ );
+ 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 mut current_scope = cx.event_scope(event).into_iter().flatten();
+ let expected_scope = expected.scope_mut();
+ let mut i = 0;
+ for (expected, actual) in expected_scope.iter_mut().zip(&mut current_scope) {
+ println!(
+ "[{}] event_scope[{}] actual={} ({:?}); expected={}",
+ self.name,
+ i,
+ actual.name(),
+ actual.id(),
+ expected
+ );
+ self.check_span_ref(
+ expected,
+ &actual,
+ format_args!("the {}th span in the event's scope to be", i),
+ );
+ i += 1;
+ }
+ let remaining_expected = &expected_scope[i..];
+ assert!(
+ remaining_expected.is_empty(),
+ "\n[{}] did not observe all expected spans in event scope!\n[{}] missing: {:#?}",
+ self.name,
+ self.name,
+ remaining_expected,
+ );
+ assert!(
+ current_scope.next().is_none(),
+ "\n[{}] did not expect all spans in the actual event scope!",
+ self.name,
+ );
+ }
+ Some(ex) => ex.bad(&self.name, format_args!("observed event {:#?}", event)),
+ }
+ }
+
+ fn on_follows_from(&self, _span: &Id, _follows: &Id, _: Context<'_, S>) {
+ // TODO: it should be possible to expect spans to follow from other spans
+ }
+
+ fn on_new_span(&self, span: &Attributes<'_>, id: &Id, cx: Context<'_, S>) {
+ let meta = span.metadata();
+ println!(
+ "[{}] new_span: name={:?}; target={:?}; id={:?};",
+ self.name,
+ meta.name(),
+ meta.target(),
+ id
+ );
+ let mut expected = self.expected.lock().unwrap();
+ 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())
+ };
+ expected.check(span, get_parent_name, &self.name);
+ }
+ }
+ }
+
+ fn on_enter(&self, id: &Id, cx: Context<'_, S>) {
+ let span = cx
+ .span(id)
+ .unwrap_or_else(|| panic!("[{}] no span for ID {:?}", self.name, id));
+ println!("[{}] enter: {}; id={:?};", self.name, span.name(), id);
+ match self.expected.lock().unwrap().pop_front() {
+ None => {}
+ Some(Expect::Enter(ref expected_span)) => {
+ self.check_span_ref(expected_span, &span, "to enter");
+ }
+ Some(ex) => ex.bad(&self.name, format_args!("entered span {:?}", span.name())),
+ }
+ self.current.lock().unwrap().push(id.clone());
+ }
+
+ fn on_exit(&self, id: &Id, cx: Context<'_, S>) {
+ if std::thread::panicking() {
+ // `exit()` can be called in `drop` impls, so we must guard against
+ // double panics.
+ println!("[{}] exit {:?} while panicking", self.name, id);
+ return;
+ }
+ let span = cx
+ .span(id)
+ .unwrap_or_else(|| panic!("[{}] no span for ID {:?}", self.name, id));
+ println!("[{}] exit: {}; id={:?};", self.name, span.name(), id);
+ match self.expected.lock().unwrap().pop_front() {
+ None => {}
+ Some(Expect::Exit(ref expected_span)) => {
+ self.check_span_ref(expected_span, &span, "to exit");
+ let curr = self.current.lock().unwrap().pop();
+ assert_eq!(
+ Some(id),
+ curr.as_ref(),
+ "[{}] exited span {:?}, but the current span was {:?}",
+ self.name,
+ span.name(),
+ curr.as_ref().and_then(|id| cx.span(id)).map(|s| s.name())
+ );
+ }
+ Some(ex) => ex.bad(&self.name, format_args!("exited span {:?}", span.name())),
+ };
+ }
+
+ fn on_close(&self, id: Id, cx: Context<'_, S>) {
+ if std::thread::panicking() {
+ // `try_close` can be called in `drop` impls, so we must guard against
+ // double panics.
+ println!("[{}] close {:?} while panicking", self.name, id);
+ return;
+ }
+ let span = cx.span(&id);
+ let name = span.as_ref().map(|span| {
+ println!("[{}] close_span: {}; id={:?};", self.name, span.name(), id,);
+ span.name()
+ });
+ if name.is_none() {
+ println!("[{}] drop_span: id={:?}", self.name, id);
+ }
+ if let Ok(mut expected) = self.expected.try_lock() {
+ let was_expected = match expected.front() {
+ Some(Expect::DropSpan(ref expected_span)) => {
+ // Don't assert if this function was called while panicking,
+ // as failing the assertion can cause a double panic.
+ if !::std::thread::panicking() {
+ if let Some(ref span) = span {
+ self.check_span_ref(expected_span, span, "to close");
+ }
+ }
+ true
+ }
+ Some(Expect::Event(_)) => {
+ if !::std::thread::panicking() {
+ panic!(
+ "[{}] expected an event, but dropped span {} (id={:?}) instead",
+ self.name,
+ name.unwrap_or("<unknown name>"),
+ id
+ );
+ }
+ true
+ }
+ _ => false,
+ };
+ if was_expected {
+ expected.pop_front();
+ }
+ }
+ }
+
+ fn on_id_change(&self, _old: &Id, _new: &Id, _ctx: Context<'_, S>) {
+ panic!("well-behaved subscribers should never do this to us, lol");
+ }
+}
+
+impl fmt::Debug for ExpectLayer {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut s = f.debug_struct("ExpectLayer");
+ s.field("name", &self.name);
+
+ if let Ok(expected) = self.expected.try_lock() {
+ s.field("expected", &expected);
+ } else {
+ s.field("expected", &format_args!("<locked>"));
+ }
+
+ if let Ok(current) = self.current.try_lock() {
+ s.field("current", &format_args!("{:?}", &current));
+ } else {
+ s.field("current", &format_args!("<locked>"));
+ }
+
+ s.finish()
+ }
+}