test(pass-through): de-flake vertex spend-log test by routing through the proxy - #31689
Conversation
The vertex pass-through spend-log test asserted that a single billed generateContent call moved the global spend aggregate within a fixed wait. CI failures show the call returning a valid response with real usage, yet spend never increasing over a 240s poll. Pass-through spend logging is best-effort: the success handler is enqueued on a background worker that can drop or time out an individual event under load and never retries it, so one billed call occasionally never reaches LiteLLM_SpendLogs. Waiting longer cannot recover a dropped event; only re-issuing the call can. Re-bill the call up to a few times and require at least one to be tracked, mirroring the sibling jest test that already retries. The test still fails hard if cost tracking is actually broken, since then every call records nothing. Also sum spend across all returned days instead of matching the runner's local 'today', removing a separate UTC-rollover flake.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…ect HTTP The vertexai SDK, configured with location="global" and an http api_endpoint override, intermittently sends generateContent to the public Vertex endpoint instead of the proxy. Proxy logs from a failing run show all 46 of the test's own spend-log polls reaching the proxy while zero generateContent calls did, so LiteLLM never saw the billed call and no spend was ever recorded; re-billing through the SDK could not help because every retry bypassed the proxy too. Issue the pass-through request directly over HTTP so it always hits the proxy, minting a Google token from the same service-account credentials, then assert that the specific call's own spend log lands with spend > 0, a gemini model, and custom_llm_provider vertex_ai. A small best-effort retry covers the rare case where the background logging worker drops a single event; failing every attempt still fails hard so the test keeps its teeth if cost tracking breaks.
Greptile SummaryRewrites
Confidence Score: 5/5Test-only change with no production code modified; the rewrite is strictly additive and the previous review comments have both been addressed. The change is confined to a single integration test file. The root cause of the flake is well-documented in the PR, the fix is mechanically sound (direct HTTP avoids the SDK endpoint-override bug), the per-call x-litellm-call-id assertion is stronger than the previous global-spend-delta check, and earlier review concerns about the async helper and hard-coded endpoint have been resolved. No files require special attention.
|
| Filename | Overview |
|---|---|
| tests/pass_through_tests/test_vertex_ai.py | Rewrites the spend-log test to use direct HTTP instead of the vertexai SDK, adding precise per-call assertion via x-litellm-call-id and fixing the previously flagged async/hardcoded-endpoint issues in the helper functions. |
Reviews (2): Last reviewed commit: "test(pass-through): reuse LITE_LLM_ENDPO..." | Re-trigger Greptile
…n get_tracked_spend
|
Generated by Claude Code |
|
bugbot run Generated by Claude Code |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 65e29fc. Configure here.
Port the de-flake of the SDK-based vertex spend test (#31689) into the tests/e2e/llm_translation harness. The vertexai SDK intermittently ignored the proxy api_endpoint override and billed Vertex directly, so the request never reached LiteLLM and no spend was logged; driving native generateContent over the shared transport always reaches the proxy, which the harness already guarantees. Credentials stay on the proxy, the same way the gemini and anthropic passthrough tests work. The gemini-2.5-flash-vertex deployment is marked use_in_pass_through, so the proxy registers its service account for the /vertex_ai route and mints the Vertex token itself; the test sends only its litellm virtual key in x-litellm-api-key and no upstream bearer, targeting that deployment's region. The Vertex credential lives in one place, the proxy's secret, and the test holds nothing and never mints a token. Asserts both that the forward succeeds and that a costed SpendLogs row lands (vertex_ai provider, a gemini model, spend > 0, call_type pass_through_endpoint), correlated by the x-litellm-call-id header.
Port the de-flake of the SDK-based vertex spend test (#31689) into the tests/e2e/llm_translation harness. The vertexai SDK intermittently ignored the proxy api_endpoint override and billed Vertex directly, so the request never reached LiteLLM and no spend was logged; driving native generateContent over the shared transport always reaches the proxy, which the harness already guarantees. The vertex deployment is added at runtime through /model/new with use_in_pass_through rather than declared in the gateway config, and deleted on teardown. That registers the deployment's service account for the /vertex_ai route, so the passthrough call sends only its litellm virtual key in x-litellm-api-key and no upstream bearer, and the proxy mints the Vertex token itself. The credential is the one the proxy already holds, read from the same VERTEXAI_CREDENTIALS/VERTEXAI_PROJECT env; the test never mints a token. Asserts both that the forward succeeds and that a costed SpendLogs row lands (vertex_ai provider, a gemini model, spend > 0, call_type pass_through_endpoint), correlated by the x-litellm-call-id header.
… the proxy (BerriAI#31689) * test(pass-through): de-flake vertex spend-log assertion by re-billing The vertex pass-through spend-log test asserted that a single billed generateContent call moved the global spend aggregate within a fixed wait. CI failures show the call returning a valid response with real usage, yet spend never increasing over a 240s poll. Pass-through spend logging is best-effort: the success handler is enqueued on a background worker that can drop or time out an individual event under load and never retries it, so one billed call occasionally never reaches LiteLLM_SpendLogs. Waiting longer cannot recover a dropped event; only re-issuing the call can. Re-bill the call up to a few times and require at least one to be tracked, mirroring the sibling jest test that already retries. The test still fails hard if cost tracking is actually broken, since then every call records nothing. Also sum spend across all returned days instead of matching the runner's local 'today', removing a separate UTC-rollover flake. * test(pass-through): route vertex spend-log test through proxy via direct HTTP The vertexai SDK, configured with location="global" and an http api_endpoint override, intermittently sends generateContent to the public Vertex endpoint instead of the proxy. Proxy logs from a failing run show all 46 of the test's own spend-log polls reaching the proxy while zero generateContent calls did, so LiteLLM never saw the billed call and no spend was ever recorded; re-billing through the SDK could not help because every retry bypassed the proxy too. Issue the pass-through request directly over HTTP so it always hits the proxy, minting a Google token from the same service-account credentials, then assert that the specific call's own spend log lands with spend > 0, a gemini model, and custom_llm_provider vertex_ai. A small best-effort retry covers the rare case where the background logging worker drops a single event; failing every attempt still fails hard so the test keeps its teeth if cost tracking breaks. * test(pass-through): reuse LITE_LLM_ENDPOINT and drop needless async in get_tracked_spend
* test(e2e): add vertex_ai passthrough spend-log coverage Port the de-flake of the SDK-based vertex spend test (#31689) into the tests/e2e/llm_translation harness. The vertexai SDK intermittently ignored the proxy api_endpoint override and billed Vertex directly, so the request never reached LiteLLM and no spend was logged; driving native generateContent over the shared transport always reaches the proxy, which the harness already guarantees. The vertex deployment is added at runtime through /model/new with use_in_pass_through rather than declared in the gateway config, and deleted on teardown. That registers the deployment's service account for the /vertex_ai route, so the passthrough call sends only its litellm virtual key in x-litellm-api-key and no upstream bearer, and the proxy mints the Vertex token itself. The credential is the one the proxy already holds, read from the same VERTEXAI_CREDENTIALS/VERTEXAI_PROJECT env; the test never mints a token. Asserts both that the forward succeeds and that a costed SpendLogs row lands (vertex_ai provider, a gemini model, spend > 0, call_type pass_through_endpoint), correlated by the x-litellm-call-id header. * Update tests/e2e/llm_translation/test_vertex_passthrough_e2e.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * Update tests/e2e/llm_translation/test_vertex_passthrough_e2e.py Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Relevant issues
tests/pass_through_tests/test_vertex_ai.py::test_basic_vertex_ai_pass_through_with_spendlogis one of the most flaky tests in the suite; CircleCI's flaky-test insights show it flaking dozens of times in the recent window inproxy_pass_through_endpoint_testsLinear ticket
N/A
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewScreenshots / Proof of Fix
The root cause is visible in the proxy container logs of a failing
proxy_pass_through_endpoint_testsrun. Across the whole window the Vertex test was executing, the proxy served all 46 of the test's ownGET /global/spend/logspolls but not a singlegenerateContent, and its only upstream forwards were to AssemblyAI and OpenAIThe 46 polls match the test's exact count (1 baseline read plus 5 attempts of 9 polls), so the window covers the full test, yet the billed
model.generate_content("hi")calls never reached LiteLLM. The vertexai SDK sent them straight to the public Vertex endpoint, which is why no spend was ever recorded and why re-billing through the SDK could not helpTo confirm the rewrite is no longer flaky, the exact CI job that owns this test (
proxy_pass_through_endpoint_tests) was rerun until it passed five times in a row on the final commit, withtest_basic_vertex_ai_pass_through_with_spendloggreen in every run (CircleCI jobs 1956777, 1957800, 1957849, 1957898, 1957899)Type
✅ Test
Changes
The test configured the vertexai SDK with
location="global"and an httpapi_endpointpointing at the proxy, then billedgenerateContentand waited for the global spend aggregate to move. With that configuration the SDK intermittently ignores the endpoint override and calls the public Vertex endpoint directly, so the request bypasses the proxy and noLiteLLM_SpendLogsrow is ever written; that bypass, not logging lag, is the flakeThis change drives the pass-through over HTTP instead of through the SDK. It mints a Google access token from the same service-account credentials the SDK would use, posts the Vertex-shaped
generateContentrequest straight to/vertex_ai/...on the proxy, and asserts that the specific call's own spend log lands withspend > 0, a gemini model, and acustom_llm_providerofvertex_ai, keyed on thex-litellm-call-idthe proxy returns. Because the request now always reaches the proxy, the only residual flake is the best-effort background logging worker occasionally dropping a single event, so the test re-bills a few times and still fails hard if no call is ever tracked. The SDK-based client path stays covered by the sibling jest test (test_vertex_with_spend.test.js)A small follow-up commit addresses the Greptile review: the
get_tracked_spendhelper used by the skipped streaming test now reuses the sharedLITE_LLM_ENDPOINTconstant instead of a hard-coded0.0.0.0:4000, and drops its needlessasyncsince it only performs a blockingrequestscallThe change is test-only; no production behavior, performance, or contract changes
Note
Low Risk
Test-only changes in
test_vertex_ai.py; no production proxy, billing, or API behavior is modified.Overview
test_basic_vertex_ai_pass_through_with_spendlogno longer bills through the vertexai SDK. It POSTsgenerateContentto the LiteLLM/vertex_ai/...URL with a Google access token, then polls/spend/logs?request_id=usingx-litellm-call-iduntil that call hasspend > 0,geminimodel, andvertex_aiprovider—retrying up to three billed calls if background logging drops an event.Shared helpers replace the old async global-spend polling:
get_tracked_spend()sums all rows from/global/spend/logs(avoids UTC “today” mismatches) and usesLITE_LLM_ENDPOINT. The skipped streaming test switches to that helper instead ofawait call_spend_logs_endpoint().Reviewed by Cursor Bugbot for commit 65e29fc. Bugbot is set up for automated code reviews on this repo. Configure here.