tracing/tracing-attributes/tests/parents.rs
Hayden Stainsby 527b4f66a6
mock: correct contextual/explicit parent assertions (#3004)
## Motivation

When recording the parent of an event or span, the `MockCollector`
treats an explicit parent of `None` (i.e. an event or span that is an
explicit root) in the same way as if there is no explicit root. This
leads to it picking up the contextual parent or treating the event or
span as a contextual root.

## Solution

This change refactors the recording of the parent to use `is_contextual`
to distinguish whether or not an explicit parent has been specified. The
actual parent is also written into an `Ancestry` enum so that the
expected and actual values can be compared in a more explicit way.

Additionally, the `Ancestry` struct has been moved into its own module and
the check behavior has been fixed. The error message has also been
unified across all cases.

Another problem with the previous API is that the two methods
`with_contextual_parent` and `with_explicit_parent` are actually
mutually exclusive, a span or event cannot be both of them. It is also a
(small) mental leap for the user to go from `with_*_parent(None)` to
understanding that this means that a span or event is a root (either
contextual or explicit).

As such, the API has been reworked into a single method `with_ancestry`,
which takes an enum with the following four variants:
* `HasExplicitParent(String)` (parent span name)
* `IsExplicitRoot`
* `HasContextualParent(String)` (parent span name)
* `IsContextualRoot`

To make the interface as useable as possible, helper functions have been
defined in the `expect` module which can be used to create the enum
variants. Specifically, these take `Into<String>` parameter for the span
name.

Given the number of different cases involved in checking ancestry,
separate integration tests have been added to `tracing-mock`
specifically for testing all the positive and negative cases when
asserting on the ancestry of events and spans.

There were two tests in `tracing-attributes` which specified both an
explicit and a contextual parent. This behavior was never intended to
work as all events and spans are either contextual or not. The tests
have been corrected to only expect one of the two.

Fixes: #2440
2024-08-05 19:03:29 +02:00

89 lines
2.5 KiB
Rust

use tracing::{collect::with_default, Id, Level};
use tracing_attributes::instrument;
use tracing_mock::*;
#[instrument]
fn with_default_parent() {}
#[instrument(parent = parent_span, skip(parent_span))]
fn with_explicit_parent<P>(parent_span: P)
where
P: Into<Option<Id>>,
{
}
#[test]
fn default_parent_test() {
let contextual_parent = expect::span().named("contextual_parent");
let child = expect::span().named("with_default_parent");
let (collector, handle) = collector::mock()
.new_span(
contextual_parent
.clone()
.with_ancestry(expect::is_contextual_root()),
)
.new_span(child.clone().with_ancestry(expect::is_contextual_root()))
.enter(child.clone())
.exit(child.clone())
.enter(contextual_parent.clone())
.new_span(
child
.clone()
.with_ancestry(expect::has_contextual_parent("contextual_parent")),
)
.enter(child.clone())
.exit(child)
.exit(contextual_parent)
.only()
.run_with_handle();
with_default(collector, || {
let contextual_parent = tracing::span!(Level::TRACE, "contextual_parent");
with_default_parent();
contextual_parent.in_scope(|| {
with_default_parent();
});
});
handle.assert_finished();
}
#[test]
fn explicit_parent_test() {
let contextual_parent = expect::span().named("contextual_parent");
let explicit_parent = expect::span().named("explicit_parent");
let child = expect::span().named("with_explicit_parent");
let (collector, handle) = collector::mock()
.new_span(
contextual_parent
.clone()
.with_ancestry(expect::is_contextual_root()),
)
.new_span(explicit_parent.with_ancestry(expect::is_contextual_root()))
.enter(contextual_parent.clone())
.new_span(
child
.clone()
.with_ancestry(expect::has_explicit_parent("explicit_parent")),
)
.enter(child.clone())
.exit(child)
.exit(contextual_parent)
.only()
.run_with_handle();
with_default(collector, || {
let contextual_parent = tracing::span!(Level::INFO, "contextual_parent");
let explicit_parent = tracing::span!(Level::INFO, "explicit_parent");
contextual_parent.in_scope(|| {
with_explicit_parent(&explicit_parent);
});
});
handle.assert_finished();
}