Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mock: unify expected span checking #3096

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 36 additions & 29 deletions tracing-mock/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ use crate::{
event::ExpectedEvent,
expect::Expect,
field::ExpectedFields,
span::{ExpectedSpan, NewSpan},
span::{ActualSpan, ExpectedSpan, NewSpan},
};
use std::{
collections::{HashMap, VecDeque},
Expand All @@ -160,19 +160,19 @@ use tracing::{
};

pub(crate) struct SpanState {
id: u64,
id: Id,
name: &'static str,
refs: usize,
meta: &'static Metadata<'static>,
}

impl SpanState {
pub(crate) fn id(&self) -> u64 {
self.id
impl ActualSpan for SpanState {
fn id(&self) -> Id {
self.id.clone()
}

pub(crate) fn metadata(&self) -> &'static Metadata<'static> {
self.meta
fn metadata(&self) -> Option<&'static Metadata<'static>> {
Some(self.meta)
}
}

Expand Down Expand Up @@ -1130,7 +1130,7 @@ where
spans.insert(
id.clone(),
SpanState {
id: id.into_u64(),
id: id.clone(),
name: meta.name(),
refs: 1,
meta,
Expand All @@ -1146,7 +1146,7 @@ where
match self.expected.lock().unwrap().pop_front() {
None => {}
Some(Expect::Enter(ref expected_span)) => {
expected_span.check(span, &self.name);
expected_span.check(span, "to enter", &self.name);
}
Some(ex) => ex.bad(&self.name, format_args!("entered span {:?}", span.name)),
}
Expand All @@ -1169,7 +1169,7 @@ where
match self.expected.lock().unwrap().pop_front() {
None => {}
Some(Expect::Exit(ref expected_span)) => {
expected_span.check(span, &self.name);
expected_span.check(span, "to exit", &self.name);
let curr = self.current.lock().unwrap().pop();
assert_eq!(
Some(id),
Expand All @@ -1185,27 +1185,34 @@ where
}

fn clone_span(&self, id: &Id) -> Id {
let name = self.spans.lock().unwrap().get_mut(id).map(|span| {
let name = span.name;
println!(
"[{}] clone_span: {}; id={:?}; refs={:?};",
self.name, name, id, span.refs
);
span.refs += 1;
name
});
if name.is_none() {
println!("[{}] clone_span: id={:?};", self.name, id);
let mut spans = self.spans.lock().unwrap();
let mut span = spans.get_mut(id);
match span.as_deref_mut() {
Some(span) => {
println!(
"[{}] clone_span: {}; id={:?}; refs={:?};",
self.name, span.name, id, span.refs,
);
span.refs += 1;
}
None => {
println!(
"[{}] clone_span: id={:?} (not found in span list);",
self.name, id
);
}
}

let mut expected = self.expected.lock().unwrap();
let was_expected = if let Some(Expect::CloneSpan(ref span)) = expected.front() {
assert_eq!(
name,
span.name(),
"[{}] expected to clone a span named {:?}",
self.name,
span.name()
);
let was_expected = if let Some(Expect::CloneSpan(ref expected_span)) = expected.front() {
match span {
Some(actual_span) => {
let actual_span: &_ = actual_span;
expected_span.check(actual_span, "to clone", &self.name);
}
// Check only by Id
None => expected_span.check(id, "to clone", &self.name),
}
true
} else {
false
Expand Down
65 changes: 43 additions & 22 deletions tracing-mock/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,69 @@ pub(crate) struct ExpectedMetadata {
}

impl ExpectedMetadata {
/// Checks the given metadata against this expected metadata and panics if
/// there is a mismatch.
///
/// The context `ctx` should fit into the followint sentence:
///
/// > expected {ctx} named `expected_name`, but got one named `actual_name`
///
/// Examples could be:
/// * a new span
/// * to enter a span
/// * an event
///
/// # Panics
///
/// This method will panic if any of the expectations that have been
/// specified are noto met.
///
pub(crate) fn check(
&self,
actual: &Metadata<'_>,
ctx: fmt::Arguments<'_>,
ctx: impl fmt::Display,
collector_name: &str,
) {
if let Some(ref expected_name) = self.name {
let name = actual.name();
let actual_name = actual.name();
assert!(
expected_name == name,
"\n[{}] expected {} to be named `{}`, but got one named `{}`",
collector_name,
ctx,
expected_name,
name
expected_name == actual_name,
"{}",
format_args!(
"\n[{collector_name}] expected {ctx} named `{expected_name}`,\n\
[{collector_name}] but got one named `{actual_name}` instead."
),
)
}

if let Some(ref expected_level) = self.level {
let level = actual.level();
let actual_level = actual.level();
assert!(
expected_level == level,
"\n[{}] expected {} to be at level `{:?}`, but it was at level `{:?}` instead",
collector_name,
ctx,
expected_level,
level,
expected_level == actual_level,
"{}",
format_args!(
"\n[{collector_name}] expected {ctx} at level `{expected_level:?}`,\n\
[{collector_name}] but got one at level `{actual_level:?}` instead."
),
)
}

if let Some(ref expected_target) = self.target {
let target = actual.target();
let actual_target = actual.target();
assert!(
expected_target == target,
"\n[{}] expected {} to have target `{}`, but it had target `{}` instead",
collector_name,
ctx,
expected_target,
target,
expected_target == actual_target,
"{}",
format_args!(
"\n[{collector_name}] expected {ctx} with target `{expected_target}`,\n\
[{collector_name}] but got one with target `{actual_target}` instead."
),
)
}
}

pub(crate) fn has_expectations(&self) -> bool {
self.name.is_some() || self.level.is_some() || self.target.is_some()
}
}

impl fmt::Display for ExpectedMetadata {
Expand Down
74 changes: 56 additions & 18 deletions tracing-mock/src/span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,7 @@
//! [`collector`]: mod@crate::collector
//! [`expect::span`]: fn@crate::expect::span
#![allow(missing_docs)]
use crate::{
ancestry::Ancestry, collector::SpanState, expect, field::ExpectedFields,
metadata::ExpectedMetadata,
};
use crate::{ancestry::Ancestry, expect, field::ExpectedFields, metadata::ExpectedMetadata};
use std::{
error, fmt,
sync::{
Expand Down Expand Up @@ -145,6 +142,24 @@ where
expect::span().named(name)
}

pub(crate) trait ActualSpan {
/// The Id of the actual span.
fn id(&self) -> tracing_core::span::Id;

/// The metadata for the actual span if it is available.
fn metadata(&self) -> Option<&'static tracing_core::Metadata<'static>>;
}

impl ActualSpan for tracing_core::span::Id {
fn id(&self) -> tracing_core::span::Id {
self.clone()
}

fn metadata(&self) -> Option<&'static tracing_core::Metadata<'static>> {
None
}
}

/// A mock span ID.
///
/// This ID makes it possible to link together calls to different
Expand Down Expand Up @@ -652,16 +667,35 @@ impl ExpectedSpan {
self.metadata.target.as_deref()
}

pub(crate) fn check(&self, actual: &SpanState, collector_name: &str) {
let meta = actual.metadata();
let name = meta.name();

pub(crate) fn check<A: ActualSpan>(
&self,
actual: &A,
ctx: impl fmt::Display,
collector_name: &str,
) {
if let Some(expected_id) = &self.id {
expected_id.check(actual.id(), format_args!("span `{}`", name), collector_name);
expected_id.check(&actual.id(), format_args!("{ctx} a span"), collector_name);
}

self.metadata
.check(meta, format_args!("span `{}`", name), collector_name);
match actual.metadata() {
Some(actual_metadata) => self.metadata.check(
actual_metadata,
format_args!("{ctx} a span"),
collector_name,
),
None => {
if self.metadata.has_expectations() {
panic!(
"{}",
format_args!(
"[{collector_name}] expected {ctx} a span with valid metadata, \
but got one with unknown Id={actual_id}",
actual_id = actual.id().into_u64()
)
);
}
}
}
}
}

Expand Down Expand Up @@ -742,9 +776,7 @@ impl NewSpan {
) {
let meta = span.metadata();
let name = meta.name();
self.span
.metadata
.check(meta, format_args!("span `{}`", name), collector_name);
self.span.metadata.check(meta, "a new span", collector_name);
let mut checker = self.fields.checker(name, collector_name);
span.record(&mut checker);
checker.finish();
Expand Down Expand Up @@ -825,20 +857,26 @@ impl ExpectedId {
Ok(())
}

pub(crate) fn check(&self, actual: u64, ctx: fmt::Arguments<'_>, collector_name: &str) {
pub(crate) fn check(
&self,
actual: &tracing_core::span::Id,
ctx: fmt::Arguments<'_>,
collector_name: &str,
) {
let id = self.inner.load(Ordering::Relaxed);
let actual = actual.into_u64();

assert!(
id != Self::UNSET,
"\n[{}] expected {} to have expected ID set, but it hasn't been, \
perhaps this `ExpectedId` wasn't used in a call to `MockCollector::new_span()`?",
"\n[{}] expected {} with an expected Id set, but it hasn't been, \
perhaps this `ExpectedId` wasn't used in a call to `new_span()`?",
collector_name,
ctx,
);

assert_eq!(
id, actual,
"\n[{}] expected {} to have ID `{}`, but it has `{}` instead",
"\n[{}] expected {} with Id `{}`, but it has Id `{}` instead",
collector_name, ctx, id, actual,
);
}
Expand Down
Loading
Loading