Skip to content

test(e2e): add vertex_ai passthrough spend-log coverage - #31761

Closed
mubashir1osmani wants to merge 1 commit into
litellm_internal_stagingfrom
litellm_vertex_passthrough_spendlog_e2e
Closed

test(e2e): add vertex_ai passthrough spend-log coverage#31761
mubashir1osmani wants to merge 1 commit into
litellm_internal_stagingfrom
litellm_vertex_passthrough_spendlog_e2e

Conversation

@mubashir1osmani

@mubashir1osmani mubashir1osmani commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Relevant issues

Companion to #31689, which de-flakes tests/pass_through_tests/test_vertex_ai.py::test_basic_vertex_ai_pass_through_with_spendlog by driving the pass-through over HTTP instead of the vertexai SDK. That SDK-bypass flake is why Vertex was the lone gap in the live passthrough matrix (tests/e2e/llm_translation/LLM_TRANSLATION_COVERAGE_MATRIX.md). This closes the non-streaming + cost cell with a real e2e test in that harness, where driving HTTP through the shared transport is the default and the SDK bypass cannot happen

Linear ticket

N/A

Pre-Submission checklist

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Screenshots / Proof of Fix

Against a live proxy hitting the real Vertex AI API and costing real dollars. The deployment is added through the management endpoint, not the config; the proxy registers its service account for the /vertex_ai route, so the passthrough call sends only its litellm virtual key and no Authorization bearer

# nothing registered yet -> passthrough is rejected
$ curl -s -o /dev/null -w "%{http_code}\n" -X POST \
    ".../vertex_ai/v1/projects/$VERTEXAI_PROJECT/locations/us-central1/publishers/google/models/gemini-2.5-flash:generateContent" \
    -H "x-litellm-api-key: sk-1234" -d '{"contents":[{"role":"user","parts":[{"text":"hi"}]}]}'
401

# add the deployment via the management endpoint with use_in_pass_through
$ curl -s -X POST .../model/new -H "Authorization: Bearer sk-1234" -d '{
    "model_name":"e2e-vertex-pt",
    "litellm_params":{"model":"vertex_ai/gemini-2.5-flash","vertex_project":"'"$VERTEXAI_PROJECT"'",
      "vertex_location":"us-central1","vertex_credentials":"<service account json>","use_in_pass_through":true},
    "model_info":{"id":"e2e-vertex-pt"}}' | jq .model_id
"e2e-vertex-pt"

# the same passthrough call now works: only the litellm key, no bearer
$ curl -sS -D - -X POST ".../vertex_ai/.../gemini-2.5-flash:generateContent" \
    -H "x-litellm-api-key: sk-1234" -d '{"contents":[{"role":"user","parts":[{"text":"reply with one word"}]}]}'
HTTP/1.1 200 OK
x-litellm-call-id: bcdd6a21-7106-4fd6-87a2-6ae3d3a5ecfd

$ curl -s ".../spend/logs?request_id=bcdd6a21-7106-4fd6-87a2-6ae3d3a5ecfd" -H "Authorization: Bearer sk-1234" | jq '.[0]'
{
  "model": "gemini-2.5-flash",
  "custom_llm_provider": "vertex_ai",
  "spend": 9.12e-05,
  "call_type": "pass_through_endpoint",
  "status": "success"
}

The test asserts both sides: the forward returns 2xx with a candidate, and that specific call's SpendLogs row lands with custom_llm_provider == "vertex_ai", a gemini model, spend > 0, call_type == "pass_through_endpoint", and status == "success". The 401-before / 200-after above is the non-vacuity: without the registered deployment the passthrough is rejected

Type

✅ Test

Changes

tests/e2e/llm_translation/test_vertex_passthrough_e2e.py adds a vertex deployment at runtime through /model/new with use_in_pass_through, drives a native generateContent request through /vertex_ai/..., asserts the costed SpendLogs row, and deletes the deployment on teardown. Adding it through the management endpoint keeps the gateway config untouched; use_in_pass_through is what makes the proxy register the deployment's service account for the passthrough route and mint the Vertex token itself, so the call carries only x-litellm-api-key and no upstream bearer. The credential is the one the proxy already holds, read from the same VERTEXAI_CREDENTIALS / VERTEXAI_PROJECT env, so the test never mints a token

passthrough_client.py gains a typed VertexHeaders model (just the litellm key) and a vertex_generate route on PassthroughClient. The matrix marks the Vertex non-streaming + cost cell covered

Deploy note: the service account needs roles/aiplatform.user, and any environment that runs this test needs VERTEXAI_PROJECT / VERTEXAI_CREDENTIALS set (the same secret the proxy uses); the test skips cleanly when they are absent

The change is test-only; no production behavior, performance, or contract changes

@codspeed-hq

codspeed-hq Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 30 untouched benchmarks


Comparing litellm_vertex_passthrough_spendlog_e2e (c5162d0) with litellm_internal_staging (a0b26d2)

Open in CodSpeed

@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds live e2e coverage for the Vertex AI passthrough spend-log path, closing the gap in the translation coverage matrix. The change is test-only and introduces no production code modifications.

  • test_vertex_passthrough_e2e.py drives a native generateContent request over /vertex_ai/... and asserts the resulting SpendLogs row carries call_type == "pass_through_endpoint", a Vertex provider, a gemini model, and spend > 0.
  • vertex_auth.py mints a short-lived Google access token from ADC using a typed Protocol to work around google.auth's missing stubs; conftest.py wraps it in a session-scoped fixture that converts ADC failures to skips.
  • passthrough_client.py gains a VertexHeaders model and a vertex_generate method, matching the shape of the existing Gemini and Anthropic helpers.

Confidence Score: 4/5

Test-only change with no production code touched; safe to merge with minor fixture design notes.

The new test and helpers are well-structured and follow established suite patterns. Two small design gaps are worth addressing before the test suite grows: the session-scoped access token can go stale after ~1 hour if a CI session is slow, and VertexHeaders is missing the tags field that both sibling header models expose, which will require another change to add tag-based Vertex coverage later.

conftest.py (session-scoped token scope) and passthrough_client.py (missing tags on VertexHeaders)

Important Files Changed

Filename Overview
tests/e2e/llm_translation/test_vertex_passthrough_e2e.py New e2e test asserting Vertex AI non-streaming passthrough records a costed SpendLogs row; well-structured and follows suite conventions.
tests/e2e/llm_translation/vertex_auth.py New helper that mints a Google ADC access token; uses a typed Protocol to compensate for google.auth's missing stubs; validates token and project before returning a typed dataclass.
tests/e2e/llm_translation/conftest.py Adds session-scoped vertex_credentials fixture that converts ADC failures to skips; the session scope means the access token could expire mid-session in long runs.
tests/e2e/llm_translation/passthrough_client.py Adds VertexHeaders model and vertex_generate route; cosmetic reformatting of existing code included. VertexHeaders omits the tags field that both sibling header models expose.
tests/e2e/llm_translation/LLM_TRANSLATION_COVERAGE_MATRIX.md Updates the coverage matrix to mark Vertex non-streaming + cost as covered and adds a description of the auth split used in the new test.

Reviews (1): Last reviewed commit: "test(e2e): add vertex_ai passthrough spe..." | Re-trigger Greptile

Comment thread tests/e2e/llm_translation/conftest.py Outdated
Comment thread tests/e2e/llm_translation/passthrough_client.py Outdated
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@mubashir1osmani
mubashir1osmani force-pushed the litellm_vertex_passthrough_spendlog_e2e branch 2 times, most recently from c5162d0 to fc7c1d6 Compare July 1, 2026 01:11
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.
@mubashir1osmani
mubashir1osmani force-pushed the litellm_vertex_passthrough_spendlog_e2e branch from fc7c1d6 to b2a59c0 Compare July 1, 2026 01:45
@mubashir1osmani

Copy link
Copy Markdown
Collaborator Author

Superseded by #31781, a clean single-commit PR with the final approach (vertex deployment added via /model/new with use_in_pass_through, no config, no client-side token minting). The review history here spans two earlier approaches that were abandoned, so closing to avoid confusion

@mubashir1osmani
mubashir1osmani deleted the litellm_vertex_passthrough_spendlog_e2e branch July 1, 2026 01:50
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.

1 participant