Support request-header matching for stub-based playback#17
Open
grdsdev wants to merge 1 commit into
Open
Conversation
Matcher.headers([...]) compares the incoming request's headers against a candidate request. For stub-based playback (.replay(stubs:)), that candidate is synthesized from a Stub with no headers ever set on it — Stub.headers only becomes the *response* headers. So .headers([...]) could never usefully match: it would only pass when the real request's named headers were absent, making it unusable for asserting an expected header value against an in-memory stub. Add Stub.requestHeaders (defaulted, source-compatible with all existing initializers) and a matchingRequestHeaders(_:) fluent modifier to set it. Playback.makeEntry(from:) now carries those headers onto the synthesized candidate request, so .headers([...]) matches as expected.
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.
Summary
Matcher.headers([...])compares an incoming request's header values against a candidate request. For HAR-based playback that candidate carries real recorded headers, so it works as documented. For stub-based playback (.replay(stubs:)), the candidate is synthesized inPlaybackStore.makeEntry(from:)from aStub— and aStubnever has request headers set on it (Stub.headersis documented as, and only used as, the response headers returned to the caller).The practical effect:
.headers([...])can never usefully match a stub. It only passes when the real request's named headers arenil, so trying to assert "this request must sendAccept: text/csv" against aStub-based test silently never matches — every request fails to find a stub, regardless of whether the code under test sent the right header.We hit this migrating a test suite off Mocker: the old tests asserted request headers (
Accept,Prefer, etc.) via Mocker's.snapshotRequestcurl output, and we reached for.headers([...])as the natural Replay equivalent — only to find it's a no-op forStub-based tests as currently implemented.Fix
Stub.requestHeaders: [String: String] = [:]— a new field, defaulted so it's source-compatible with every existing initializer and call site.Stub.matchingRequestHeaders(_:), a fluent modifier for setting it inline in a stub list literal, e.g.:PlaybackStore.makeEntry(from:)now carriesstub.requestHeadersonto the synthesized candidate request, soMatcher.headers([...])matches as expected..headerscase doc comment to call out the stub-based caveat explicitly, so the next person doesn't have to rediscover this from source.Test plan
PlaybackTests.swift:requestHeadersnever matches.headers([...]), even though the real request sets the header)matchingRequestHeadersmakes the match succeed, and a mismatched header value still correctly fails)swift test— 345/345 passing.swift-format lintclean on all changed files.