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: match parent span on ExpectedSpan #3098

Merged
merged 5 commits into from
Oct 30, 2024
Merged

Conversation

hds
Copy link
Contributor

@hds hds commented Oct 4, 2024

Motivation

The with_ancestry methods on NewSpan and ExpectedEvent provide a
way to match whether the span or event is a contextual or explicit root
or if it has a contextual or explicit parent span.

However, in the case of matching on a contextual or explicit parent
span, only the span name could be used for matching. This is
sufficiently precise when testing tracing instrumentation in other
libraries or applications as opposed to testing tracing itself.

It is likely that a user would like to test that some span or event has
a specific span as a parent, and not just any span with a specific name,
in many cases, all the possible parent spans may have the same name.
This is the case when testing tracing instrumentation in Tokio.

Solution

To solve this problem, the Ancestry struct was renamed to
ExpectedAncestry and in the case of expecting an explicit or
conextual parent, an ExpectedSpan object can be passed in. This
provides the maximum possible flexibility.

The convenience functions in the expect module now take
Into<ExpectedSpan> so that existing tests that pass a string type
object for the parent will see the same behaviour as previously and
shorthand use for expected Ids is also available.

Additionally, the span checking code has been unified between the
MockCollector and MockSubscriber cases and the assertion
descriptions have been improved to make them more readable.

@hds hds requested review from hawkw, davidbarsky and a team as code owners October 4, 2024 16:17
@hds hds force-pushed the hds/mock-parent-by-expected-span branch from 0ea1cfe to 1f5c9a7 Compare October 4, 2024 16:22
@hds hds force-pushed the hds/mock-into-expected-span branch from 5daa282 to f3570da Compare October 16, 2024 10:24
@hds hds force-pushed the hds/mock-parent-by-expected-span branch from 1f5c9a7 to f1068c5 Compare October 16, 2024 10:25
Many of the methods on `MockCollector` take an `ExpectedSpan`. This
often requires significant boilerplate. For example, to expect that a
span with a specific name enters and then exits, the following code is
needed:

```rust
let span = expect::span().named("span name");

let (collector, handle) = collector::mock()
    .enter(span.clone())
    .exit(span)
    .run_with_handle();
```

In order to make using `tracing-mock` more ergonomic and also more
compact, the `MockCollector` and `MockSubscriber` methods that previous
took an `ExpectedSpan`, are now generic over `Into<ExpectedSpan>`.

There are currently 3 implementations of `From` for `ExpectedSpan` which
allow the following shorthand uses:

`T: Into<String>` - an `ExpectedSpan` will be created that expects to
have a name specified by `T`.

```rust
let (collector, handle) = collector::mock()
    .enter("span name")
    .exit("span name")
    .run_with_handle();
```

`&ExpectedId` - an `ExpectedSpan` will be created that expects to have
the expected Id. A reference is taken and cloned internally because the
caller always needs to use an `ExpectedId` in at least 2 calls to the
mock collector/subscriber.

```rust
let id = expect::id();

let (collector, handle) = collector::mock()
    .new_span(&id)
    .enter(&id)
    .run_with_handle();
```

`&ExpectedSpan` - The expected span is taken by reference and cloned.

```rust
let span = expect::span().named("span name");

let (collector, handle) = collector::mock()
    .enter(&span)
    .exit(&span)
    .run_with_handle();
```

In Rust, taking a reference to an object and immediately cloning it is
an anti-pattern. It is considered better to force the user to clone
outside the API to make the cloning explict.

However, in the case of a testing framework, it seems reasonable to
prefer a more concise API, rather than having it more explicit.

To reduce the size of this PR and to avoid unnecessary churn in other
crates, the tests within the tracing repo which use `tracing-mock` will
not be updated to use the new `Into<ExpectedSpan>` capabilities. The new
API is backwards compatible and those tests can remain as they are.
@hds hds force-pushed the hds/mock-into-expected-span branch from f3570da to 8c80981 Compare October 17, 2024 12:57
The `with_ancestry` methods on `NewSpan` and `ExpectedEvent` provide a
way to match whether the span or event is a contextual or explicit root
or if it has a contextual or explicit parent span.

However, in the case of matching on a contextual or explicit parent
span, only the span name could be used for matching. This is
sufficiently precise when testing tracing instrumentation in other
libraries or applications as opposed to testing tracing itself.

It is likely that a user would like to test that some span or event has
a specific span as a parent, and not just any span with a specific name,
in many cases, all the possible parent spans may have the same name.
This is the case when testing tracing instrumentation in Tokio.

To solve this problem, the `Ancestry` struct was renamed to
`ExpectedAncestry` and in the case of expecting an explicit or
conextual parent, an `ExpectedSpan` object can be passed in. This
provides the maximum possible flexibility.

The convenience functions in the `expect` module now take
`Into<ExpectedSpan>` so that existing tests that pass a string type
object for the parent will see the same behaviour as previously and
shorthand use for expected Ids is also available.

Additionally, the span checking code has been unified between the
`MockCollector` and `MockSubscriber` cases and the assertion
descriptions have been improved to make them more readable.
@hds hds force-pushed the hds/mock-parent-by-expected-span branch from f1068c5 to 39438f4 Compare October 17, 2024 12:57
Base automatically changed from hds/mock-into-expected-span to master October 29, 2024 14:38
@hds hds merged commit 21c5ce0 into master Oct 30, 2024
56 checks passed
@hds hds deleted the hds/mock-parent-by-expected-span branch October 30, 2024 14:31
hds added a commit that referenced this pull request Nov 9, 2024
The `with_ancestry` methods on `NewSpan` and `ExpectedEvent` provide a
way to match whether the span or event is a contextual or explicit root
or if it has a contextual or explicit parent span.

However, in the case of matching on a contextual or explicit parent
span, only the span name could be used for matching. This is
sufficiently precise when testing tracing instrumentation in other
libraries or applications as opposed to testing tracing itself.

It is likely that a user would like to test that some span or event has
a specific span as a parent, and not just any span with a specific name,
in many cases, all the possible parent spans may have the same name.
This is the case when testing tracing instrumentation in Tokio.

To solve this problem, the `Ancestry` struct was renamed to
`ExpectedAncestry` and in the case of expecting an explicit or
conextual parent, an `ExpectedSpan` object can be passed in. This
provides the maximum possible flexibility.

The convenience functions in the `expect` module now take
`Into<ExpectedSpan>` so that existing tests that pass a string type
object for the parent will see the same behaviour as previously and
shorthand use for expected Ids is also available.

Additionally, the span checking code has been unified between the
`MockCollector` and `MockSubscriber` cases and the assertion
descriptions have been improved to make them more readable.
hds added a commit that referenced this pull request Nov 20, 2024
The `with_ancestry` methods on `NewSpan` and `ExpectedEvent` provide a
way to match whether the span or event is a contextual or explicit root
or if it has a contextual or explicit parent span.

However, in the case of matching on a contextual or explicit parent
span, only the span name could be used for matching. This is
sufficiently precise when testing tracing instrumentation in other
libraries or applications as opposed to testing tracing itself.

It is likely that a user would like to test that some span or event has
a specific span as a parent, and not just any span with a specific name,
in many cases, all the possible parent spans may have the same name.
This is the case when testing tracing instrumentation in Tokio.

To solve this problem, the `Ancestry` struct was renamed to
`ExpectedAncestry` and in the case of expecting an explicit or
conextual parent, an `ExpectedSpan` object can be passed in. This
provides the maximum possible flexibility.

The convenience functions in the `expect` module now take
`Into<ExpectedSpan>` so that existing tests that pass a string type
object for the parent will see the same behaviour as previously and
shorthand use for expected Ids is also available.

Additionally, the span checking code has been unified between the
`MockCollector` and `MockSubscriber` cases and the assertion
descriptions have been improved to make them more readable.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants