Skip to content

Commit

Permalink
mock: complete API documentation including expect module (#2494)
Browse files Browse the repository at this point in the history
## Motivation

There has been interest around publishing tracing-mock to crates.io
for some time. In order to make this possible, documentation and some
code clean up is needed.

The `expect` module, which contains constructor functions for many of
the other `tracing-mock` modules needs documentation and examples.

This change adds documentation to the `expect` module and all the public
APIs within it. This includes doctests on all the methods which serve as
examples.

## Solution

The lint for `missing_docs` has been enabled for the entire
`tracing-mock` crate! This has been done together with all the
other lints that are enabled on the other crates in this project.

The `event::msg("message")` constructor was removed, in favor of
requiring an explicit construction via
`expect::event().with_fields(expect::msg("message"))`. This is
appropriate to reduce the API surface that would need to be supported in
the future and also because the `event::msg` constructor could be
overridden by a subsequent usage of `with_fields`. The shorthand
`expect::message()` was renamed to `expect::msg` to make this
change less burdensome.

The `span::named("name")` constructor was removed, in favor of requiring
an explicit construction via `expect::span.with_name("name")`. The
latter isn't much longer and since #3097, a string with the name can
be passed directly everywhere that an `ExpectedSpan` is required.

This change also sets the `missing_docs` lint to warn for the entire
`tracing-mock` crate, making it ready to publish (once backported).

Refs: #539
  • Loading branch information
hds authored Nov 2, 2024
1 parent 21c5ce0 commit 91fedc1
Show file tree
Hide file tree
Showing 15 changed files with 387 additions and 126 deletions.
10 changes: 5 additions & 5 deletions tracing-mock/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# tracing-mock

Utilities for testing [`tracing`][tracing] and crates that uses it.
Utilities for testing [`tracing`] and crates that uses it.

[![Documentation (master)][docs-master-badge]][docs-master-url]
[![MIT licensed][mit-badge]][mit-url]
Expand Down Expand Up @@ -78,7 +78,7 @@ fn yak_shaving() {
}

let (collector, handle) = collector::mock()
.event(expect::event().with_fields(expect::message("preparing to shave yaks")))
.event(expect::event().with_fields(expect::msg("preparing to shave yaks")))
.only()
.run_with_handle();

Expand Down Expand Up @@ -128,15 +128,15 @@ let (collector, handle) = collector::mock()
expect::event().with_fields(
expect::field("number_of_yaks")
.with_value(&yak_count)
.and(expect::message("preparing to shave yaks"))
.and(expect::msg("preparing to shave yaks"))
.only(),
),
)
.event(
expect::event().with_fields(
expect::field("all_yaks_shaved")
.with_value(&true)
.and(expect::message("yak shaving completed."))
.and(expect::msg("yak shaving completed."))
.only(),
),
)
Expand Down Expand Up @@ -173,4 +173,4 @@ This project is licensed under the [MIT license][mit-url].

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in Tracing by you, shall be licensed as MIT, without any additional
terms or conditions.
terms or conditions.
26 changes: 15 additions & 11 deletions tracing-mock/src/collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
//!
//! let (collector, handle) = collector::mock()
//! // Expect a single event with a specified message
//! .event(expect::event().with_fields(expect::message("droids")))
//! .event(expect::event().with_fields(expect::msg("droids")))
//! .only()
//! .run_with_handle();
//!
Expand Down Expand Up @@ -40,7 +40,7 @@
//! // Enter a matching span
//! .enter(&span)
//! // Record an event with message "collect parting message"
//! .event(expect::event().with_fields(expect::message("collect parting message")))
//! .event(expect::event().with_fields(expect::msg("collect parting message")))
//! // Record a value for the field `parting` on a matching span
//! .record(&span, expect::field("parting").with_value(&"goodbye world!"))
//! // Exit a matching span
Expand Down Expand Up @@ -81,7 +81,7 @@
//! .named("my_span");
//! let (collector, handle) = collector::mock()
//! .enter(&span)
//! .event(expect::event().with_fields(expect::message("collect parting message")))
//! .event(expect::event().with_fields(expect::msg("collect parting message")))
//! .record(&span, expect::field("parting").with_value(&"goodbye world!"))
//! .exit(span)
//! .only()
Expand Down Expand Up @@ -137,13 +137,6 @@
//!
//! [`Collect`]: trait@tracing::Collect
//! [`MockCollector`]: struct@crate::collector::MockCollector
use crate::{
ancestry::get_ancestry,
event::ExpectedEvent,
expect::Expect,
field::ExpectedFields,
span::{ActualSpan, ExpectedSpan, NewSpan},
};
use std::{
collections::{HashMap, VecDeque},
sync::{
Expand All @@ -152,13 +145,22 @@ use std::{
},
thread,
};

use tracing::{
collect::Interest,
level_filters::LevelFilter,
span::{self, Attributes, Id},
Collect, Event, Metadata,
};

use crate::{
ancestry::get_ancestry,
event::ExpectedEvent,
expect::Expect,
field::ExpectedFields,
span::{ActualSpan, ExpectedSpan, NewSpan},
};

pub(crate) struct SpanState {
id: Id,
name: &'static str,
Expand Down Expand Up @@ -188,6 +190,7 @@ struct Running<F: Fn(&Metadata<'_>) -> bool> {
/// for the methods and the [`collector`] module.
///
/// [`collector`]: mod@crate::collector
#[derive(Debug)]
pub struct MockCollector<F: Fn(&Metadata<'_>) -> bool> {
expected: VecDeque<Expect>,
max_level: Option<LevelFilter>,
Expand All @@ -204,6 +207,7 @@ pub struct MockCollector<F: Fn(&Metadata<'_>) -> bool> {
/// module documentation.
///
/// [`collector`]: mod@crate::collector
#[derive(Debug)]
pub struct MockHandle(Arc<Mutex<VecDeque<Expect>>>, String);

/// Create a new [`MockCollector`].
Expand All @@ -223,7 +227,7 @@ pub struct MockHandle(Arc<Mutex<VecDeque<Expect>>>, String);
/// // Enter a matching span
/// .enter(&span)
/// // Record an event with message "collect parting message"
/// .event(expect::event().with_fields(expect::message("collect parting message")))
/// .event(expect::event().with_fields(expect::msg("collect parting message")))
/// // Record a value for the field `parting` on a matching span
/// .record(&span, expect::field("parting").with_value(&"goodbye world!"))
/// // Exit a matching span
Expand Down
11 changes: 3 additions & 8 deletions tracing-mock/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,15 @@
//!
//! [`collector`]: mod@crate::collector
//! [`expect::event`]: fn@crate::expect::event
#![allow(missing_docs)]
use std::fmt;

use crate::{
ancestry::{ActualAncestry, ExpectedAncestry},
expect, field,
field,
metadata::ExpectedMetadata,
span,
};

use std::fmt;

/// An expected event.
///
/// For a detailed description and examples, see the documentation for
Expand All @@ -52,10 +51,6 @@ pub struct ExpectedEvent {
pub(super) metadata: ExpectedMetadata,
}

pub fn msg(message: impl fmt::Display) -> ExpectedEvent {
expect::event().with_fields(expect::message(message))
}

impl ExpectedEvent {
/// Sets a name to expect when matching an event.
///
Expand Down
205 changes: 198 additions & 7 deletions tracing-mock/src/expect.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,25 @@
//! Construct expectations for traces which should be received
//!
//! This module contains constructors for expectations defined
//! in the [`event`], [`span`], and [`field`] modules.
//!
//! # Examples
//!
//! ```
//! use tracing_mock::{collector, expect};
//!
//! let (collector, handle) = collector::mock()
//! // Expect an event with message
//! .event(expect::event().with_fields(expect::msg("message")))
//! .only()
//! .run_with_handle();
//!
//! tracing::collect::with_default(collector, || {
//! tracing::info!("message");
//! });
//!
//! handle.assert_finished();
//! ```
use std::fmt;

use crate::{
Expand All @@ -23,12 +45,141 @@ pub(crate) enum Expect {
Nothing,
}

/// Create a new [`ExpectedEvent`].
///
/// For details on how to add additional assertions to the expected
/// event, see the [`event`] module and the [`ExpectedEvent`] struct.
///
/// # Examples
///
/// ```
/// use tracing_mock::{collector, expect};
///
/// let (collector, handle) = collector::mock()
/// .event(expect::event())
/// .run_with_handle();
///
/// tracing::collect::with_default(collector, || {
/// tracing::info!(field.name = "field_value");
/// });
///
/// handle.assert_finished();
/// ```
///
/// If we expect an event and instead record something else, the test
/// will fail:
///
/// ```should_panic
/// use tracing_mock::{collector, expect};
///
/// let (collector, handle) = collector::mock()
/// .event(expect::event())
/// .run_with_handle();
///
/// tracing::collect::with_default(collector, || {
/// let span = tracing::info_span!("span");
/// let _guard = span.enter();
/// });
///
/// handle.assert_finished();
/// ```
pub fn event() -> ExpectedEvent {
ExpectedEvent {
..Default::default()
}
}

/// Construct a new [`ExpectedSpan`].
///
/// For details on how to add additional assertions to the expected
/// span, see the [`span`] module and the [`ExpectedSpan`] and
/// [`NewSpan`] structs.
///
/// # Examples
///
/// ```
/// use tracing_mock::{collector, expect};
///
/// let (collector, handle) = collector::mock()
/// .new_span(expect::span())
/// .enter(expect::span())
/// .run_with_handle();
///
/// tracing::collect::with_default(collector, || {
/// let span = tracing::info_span!("span");
/// let _guard = span.enter();
/// });
///
/// handle.assert_finished();
/// ```
///
/// If we expect to enter a span and instead record something else, the test
/// will fail:
///
/// ```should_panic
/// use tracing_mock::{collector, expect};
///
/// let (collector, handle) = collector::mock()
/// .enter(expect::span())
/// .run_with_handle();
///
/// tracing::collect::with_default(collector, || {
/// tracing::info!(field.name = "field_value");
/// });
///
/// handle.assert_finished();
/// ```
pub fn span() -> ExpectedSpan {
ExpectedSpan {
..Default::default()
}
}

/// Construct a new [`ExpectedField`].
///
/// For details on how to set the value of the expected field and
/// how to expect multiple fields, see the [`field`] module and the
/// [`ExpectedField`] and [`ExpectedFields`] structs.
/// span, see the [`span`] module and the [`ExpectedSpan`] and
/// [`NewSpan`] structs.
///
/// # Examples
///
/// ```
/// use tracing_mock::{collector, expect};
///
/// let event = expect::event()
/// .with_fields(expect::field("field.name").with_value(&"field_value"));
///
/// let (collector, handle) = collector::mock()
/// .event(event)
/// .run_with_handle();
///
/// tracing::collect::with_default(collector, || {
/// tracing::info!(field.name = "field_value");
/// });
///
/// handle.assert_finished();
/// ```
///
/// A different field value will cause the test to fail:
///
/// ```should_panic
/// use tracing_mock::{collector, expect};
///
/// let event = expect::event()
/// .with_fields(expect::field("field.name").with_value(&"field_value"));
///
/// let (collector, handle) = collector::mock()
/// .event(event)
/// .run_with_handle();
///
/// tracing::collect::with_default(collector, || {
/// tracing::info!(field.name = "different_field_value");
/// });
///
/// handle.assert_finished();
/// ```
pub fn field<K>(name: K) -> ExpectedField
where
String: From<K>,
Expand All @@ -39,19 +190,59 @@ where
}
}

pub fn message(message: impl fmt::Display) -> ExpectedField {
/// Construct a new message [`ExpectedField`].
///
/// For details on how to set the value of the message field and
/// how to expect multiple fields, see the [`field`] module and the
/// [`ExpectedField`] and [`ExpectedFields`] structs.
///
/// This is equivalent to
/// `expect::field("message").with_value(message)`.
///
/// # Examples
///
/// ```
/// use tracing_mock::{collector, expect};
///
/// let event = expect::event().with_fields(
/// expect::msg("message"));
///
/// let (collector, handle) = collector::mock()
/// .event(event)
/// .run_with_handle();
///
/// tracing::collect::with_default(collector, || {
/// tracing::info!("message");
/// });
///
/// handle.assert_finished();
/// ```
///
/// A different message value will cause the test to fail:
///
/// ```should_panic
/// use tracing_mock::{collector, expect};
///
/// let event = expect::event().with_fields(
/// expect::msg("message"));
///
/// let (collector, handle) = collector::mock()
/// .event(event)
/// .run_with_handle();
///
/// tracing::collect::with_default(collector, || {
/// tracing::info!("different message");
/// });
///
/// handle.assert_finished();
/// ```
pub fn msg(message: impl fmt::Display) -> ExpectedField {
ExpectedField {
name: "message".to_string(),
value: ExpectedValue::Debug(message.to_string()),
}
}

pub fn span() -> ExpectedSpan {
ExpectedSpan {
..Default::default()
}
}

/// Returns a new, unset `ExpectedId`.
///
/// The `ExpectedId` needs to be attached to a [`NewSpan`] or an
Expand Down
Loading

0 comments on commit 91fedc1

Please sign in to comment.