test(processor): add unit tests for response.go's ProcessResponse - #610
Open
kalra-mohit wants to merge 1 commit into
Open
test(processor): add unit tests for response.go's ProcessResponse#610kalra-mohit wants to merge 1 commit into
kalra-mohit wants to merge 1 commit into
Conversation
The file already had RestorePII/BuildRestorer coverage, but its main exported entry point, ProcessResponse, had none. Adds tests for: the content-type gate (non-JSON bodies pass through untouched), malformed JSON falling back to the original body, a real end-to-end restore through a genuine OpenAIProvider (masked value restored, original_response preserved as raw untouched bytes, proxy_metadata stamped), an unmapped masked token being left alone rather than corrupted (the "mapping miss" case), the provider-returns-an-error path still stamping metadata instead of aborting, and the interception-notice wiring. providers.Provider can't be faked from this package — CreateMaskedRequest and RestoreMaskedResponse are typed against unexported function types declared in package providers, so only types in that package can satisfy the interface. Tests use a real OpenAIProvider instead (it makes no network calls until a request is actually sent), matching the existing convention in proxy/handler_test.go rather than inventing a workaround. Closes dataiku#429 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Contributor
|
All contributors have signed the CLA ✍️ ✅ |
kalra-mohit
added a commit
to kalra-mohit/kiji-proxy
that referenced
this pull request
Jul 22, 2026
First-time contribution, per CONTRIBUTING.md's requirement to add yourself to CONTRIBUTORS.md in your first PR. Adding here since this is the first of three PRs from this contribution; the other two (dataiku#610, dataiku#611) reference this instead of duplicating the entry. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Author
|
I have read the CLA Document and I hereby sign the CLA |
Author
|
I have read the CLA Document and I hereby sign the CLA |
Author
|
recheck |
kalra-mohit
marked this pull request as ready for review
July 22, 2026 02:30
Author
|
@hanneshapke whenever you get a chance to take a look, happy to address any feedback! |
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.
Closes #429.
response.goalready had decent coverage onRestorePII/BuildRestorer, butProcessResponse— the function that actually gets called on every response — had none. This adds it.ProcessResponse's job, stripped down: gate on content type, try to parse the body as JSON (fall back to the original bytes if it doesn't parse), hand off to the provider'sRestoreMaskedResponsefor the actual PII restoration, then stamporiginal_responseandproxy_metadataonto the result.What's covered:
choices[0].message.contentgets restored to the real value,original_responseholds the untouched input bytes, andproxy_metadatagets stamped.original_responseis embedded viajson.RawMessage, so it comes back as nested JSON rather than a string when you unmarshal the result — took me a second to realize the test needed to account for that instead of comparing it as a plain string.maskedToOriginal, it's left exactly as-is — not corrupted, not blanked.RestoreMaskedResponseerrors on something without achoicesfield):ProcessResponsejust logs it and keeps going, andproxy_metadatastill gets added. That distinction matters — a caller shouldn't be able to tell "nothing needed restoring" apart from "the proxy gave up silently."ProcessResponsebuilds, and thegetAddProxyNoticecallback it passes down, actually reachOpenAIProviderand show up in the response content.Why a real
OpenAIProviderinstead of a mock:providers.Provider'sCreateMaskedRequestandRestoreMaskedResponseare typed against unexported function types declared inside packageproviders(maskPIIInTextType,restorePIIType, etc.), so nothing defined outside that package can satisfy the interface — a hand-rolled fake fromprocessor_testsimply won't compile. I noticedproxy/handler_test.goalready deals with this the same way (constructs a realOpenAIProvider, which is cheap since it makes no network calls until you actually send a request), so I followed that existing pattern instead of inventing a different one.One thing I left deliberately undone: the
json.Marshalfailure fallback (the branch where re-marshaling the modified response fails andProcessResponsereturns the original body) isn't separately tested. Triggering it needs a provider to write something unmarshalable — a channel, a func — into the decoded response map, and every real provider only ever writes strings. Given the same unexported-interface constraint above, there's no way to force that branch through the public API without a fake, which isn't buildable here. I left a comment explaining that rather than skip it silently.This repo requires first-time contributors to add themselves to
CONTRIBUTORS.md; that entry is in #609 (one of three PRs from the same pass), not duplicated here.flowchart LR A[Incoming response body\n+ contentType + maskedToOriginal] --> B{JSON content type?} B -->|no| C[return body unchanged]:::covered B -->|yes| D{json.Unmarshal succeeds?} D -->|no, malformed| E[return original body]:::covered D -->|yes| F["provider.RestoreMaskedResponse\n(e.g. OpenAIProvider)"] F -->|error - unrecognized shape| G[log only, keep going]:::covered F -->|ok| H["response with PII\nrestored in place\n(unmapped tokens left as-is)"]:::covered G --> I[stamp original_response\n+ proxy_metadata]:::covered H --> I I --> J{json.Marshal succeeds?} J -->|yes| K[return modified JSON]:::covered J -->|no - not reachable\nvia public API today| L[return original body]:::uncovered classDef covered fill:#1f4d2c,stroke:#27ae60,color:#fff classDef uncovered stroke-dasharray: 5 5Test plan:
go test ./src/backend/processor/...passesgo vetandgofmt -lcleanoriginal_responsefield and the provider-error-keeps-going behavior — I temporarily removed the field and made the error path return early instead of continuing, confirmed both new tests failed as expected, then reverted