refactor(test-utils): one tracing capture layer for span and event assertions - #2659
Merged
gold-silver-copper merged 4 commits intoOct 1, 2026
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
refactor(test-utils): one tracing capture layer for span and event assertions
Description
Smell: duplicated test fixtures. The unit tests of
rig-coreandrig-agent, plus one cassette driver, asserted on telemetry through twelve hand-writtentracing_subscriber::Layer+Visitpairs. Each one re-implemented "remember every span's name, target, parent and fields" or "remember every WARN event's message":rig-core/src/driver/dyn_model/tests.rsSpans,Valuesrig-core/src/telemetry/equivalence_tests.rsSpans,Values(a copy of the one above, plus parents)rig-core/src/telemetry/tests.rsModalityCapture*,CapturedFields/FieldCapture*,CapturedWarnings/WarningCapture*,CapturedSpan/SpanCaptureLayer/StringFieldVisitor,contains_stringrig-core/src/driver/tests.rsRecordFields, an inlineWarningslayer, a sharedVisitrig-agent/src/agent/streaming/tests.rsCapturedSpan(s),SpanCaptureLayer, two visitors,CapturedFieldrig-agent/src/agent/engine/tests.rsCaptured/CaptureLayer/FieldVisitor,ResultValueLayer/ResultValueVisitorrig-agent/src/agent/builder/tests.rsWarningslayerrig-cassette/tests/common/request_identity.rsRecorded,Visitor,CaptureWhy it hurts. Every copy made its own choice about which
record_*methods it overrides (one silently dropped every&strintoDebugquoting, another ignored non-u64fields, another kept only the newest span and attached everyrecordcall to it whatever its id), whether it sees creation-time values or onlyrecordcalls, how it stringifies numbers, and how it resolves parents. A new telemetry test had to pick one of twelve slightly different captures, or write a thirteenth.Change.
rig_core::test_utils::TraceCapture(behind the existingtest-utilsfeature) is one layer that records, per span, its id, name, target, parent, declared fields, creation-time values, every laterrecordcall in order and itsfollows_fromedges, and, per event, its level, target and fields. Values are JSON (strings stay strings, integers are numbers). Every copy above now uses it. Each test keeps its assertions and the same view of the trace it asserted on: creation-time values vs later recordings (initial/recorded/record_count), all values of a field across spans (values_of), the last span (last_span), WARN messages (warnings), or WARN-and-above events (the builder test filtersevents()itself to keep its>= WARNscope).Measured:
git diff --shortstat origin/main...HEAD= 13 files changed, 582 insertions(+), 1366 deletions(-): net LOC -784. The shared layer is ~250 lines including docs and a doctest.Decisions
rig_core::test_utils(notrig-test-support) becauserig-core's andrig-agent's own unit tests need it, and they cannot depend on the facade-level support crate. That makestracing-subscriberan optionalrig-coredependency enabled only bytest-utils; it was already a dev-dependency, soCargo.lockgains nothing. Checked:cargo check -p rig-core --no-default-features --features test-utils --lib --target wasm32-unknown-unknown.rig-cassette'stracing-subscriberdev-dependency is removed:request_identity.rswas its only user.Some("\"embeddings\"")becameSome(json!("embeddings")),Some("4")becameSome(json!(4))). These are the same recorded values in a typed form, not weaker checks.telemetry::tests' oldSpanCaptureLayerkept only the most recent span and attached everyrecordcall to it. The tests now readlast_span(), whoserecordedholds only that span's own recordings. Every such test asserts on recordings made to the span it reads, so they all still pass, and a stray recording on another span can no longer satisfy them by accident.Rejected candidates in this lane
recorded_request/recorded_response/recorded_stream_chunkswrappers in17 OpenRouter/OpenAI/Mistral/DeepSeek cassette matrix files: each is a 3-line wrapper over an existing-150) and doesn't remove a real abstraction, and it would add churn next to chore: derive cassette suites from the tree and sort-check manifest lists #2437's cassette work.crate::cassettes::recorded_*helper that pins the provider name. Inlining them is cosmetic (scripted_unaryin 11ecs_faults/ecs_matrix_long_loopfiles: the bodies differ in client, wire, model and thinking dialect. A shared constructor would save ~5 lines per copy and add a generic signature, so roughly -40 net. Not worth it.text_of/tool_request/drainhelpers: they share a name but take different types and do different work. Not real duplication.Changelog
rig_core::test_utils::TraceCapture, atracinglayer that records spans (values at creation and every later recording, parents,follows_from) and events for test assertions. Thetest-utilsfeature now enablestracing-subscriber.Migration
None.
Type of change
test-utilsaddition)Testing
cargo nextest run --locked --profile local -p rig-core --lib: 1516 passedcargo nextest run --locked --profile local -p rig-agent --lib: 661 passedcargo test --locked -p rig-core --doc: includes the newtrace_capturedoctestRIG_PROVIDER_TEST_MODE=replay cargo nextest run --locked --profile local -p rig-cassette --all-features --test <groq|xai|anthropic|openai> request_identity: all passed (cassettes replayed, none recorded or changed)cargo clippy --locked -p rig-core -p rig-agent --all-features --tests -- -D warningscargo check --locked -p rig-core --no-default-features --features test-utils --lib --target wasm32-unknown-unknownChecklist:
CHANGELOG.mdorMIGRATING.md(they are generated at release)Notes
No cassette, golden or recorded request changed.