test: point router/completion/triton tests at the local fake OpenAI endpoint - #30900
Conversation
…ndpoint The shared Railway-hosted mock (exampleopenaiendpoint-production.up.railway.app) takes down unrelated CI jobs whenever it is unreachable. #30695 moved the mounted proxy configs onto a job-local fake server but left these in-Python api_base literals pointing at the dead host, so litellm_router_testing, local_testing_part1, local_testing_part2 and llm_translation_testing still fail with a 404 "Application not found" when Railway is down Resolve the api_base from FAKE_OPENAI_API_BASE (default http://127.0.0.1:8190) through a shared helper, auto-start the canned server from the local_testing and llm_translation conftests when nothing is already serving, and extend the server with a Triton embeddings route and a slow-endpoint delay so the triton and latency-timeout tests run fully offline. The deliberately broken fallback URL is left as-is so fallback handling still has a failing upstream
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Generated by Claude Code |
Greptile SummaryThis PR decouples router, completion, Triton, and related tests from the shared Railway-hosted fake OpenAI endpoint by introducing a local mock server helper and pointing all hardcoded
Confidence Score: 5/5Safe to merge — all changes are test infrastructure only; no production LiteLLM runtime paths are touched. Every change is isolated to the test layer. The helper design decisions (no atexit teardown, loopback-only env honoring, lru_cache per process) are sound and well-documented. The one minor gap is the Railway-URL regex guard not covering single-quoted or comma-terminated strings, but this does not affect CI correctness. No files require special attention.
|
| Filename | Overview |
|---|---|
| tests/fake_openai_endpoint.py | New shared helper that resolves FAKE_OPENAI_API_BASE, health-checks it, and spawns the canned server when needed; well-documented design choices |
| tests/_fake_openai_endpoint_server.py | Adds /triton/embeddings route and slow-endpoint sleep logic; both are inert for existing proxy E2E tests |
| tests/local_testing/test_fake_openai_endpoint.py | New regression test covering chat shape, Triton route, slow-endpoint delay, and a regex guard against Railway URLs re-appearing; guard regex has a minor gap with single-quoted strings |
| tests/local_testing/conftest.py | Adds session-scoped autouse fixture to start the fake endpoint and excludes the new test file from VCR recording |
| tests/llm_translation/conftest.py | Same session-scoped autouse fixture pattern as local_testing/conftest.py |
| tests/local_testing/test_lowest_latency_routing.py | Replaces Railway URLs with FAKE_OPENAI_API_BASE; slow-endpoint behavior now served locally via the 3s sleep in the canned server |
| tests/local_testing/test_router_fallback_handlers.py | URL swap and updates the assertion on _hidden_params["api_base"] to match the new local base |
| tests/llm_translation/test_triton.py | Points Triton embedding test at the new /triton/embeddings route on the local server |
| tests/local_testing/test_router.py | Replaces Railway URL literals with the FAKE_OPENAI_API_BASE constant |
| tests/local_testing/test_router_fallbacks.py | URL swap for two router configurations; test logic and assertions unchanged |
| tests/local_testing/test_router_custom_routing.py | URL swap in _create_router(); no logic changes |
| tests/local_testing/test_secret_detect_hook.py | URL swap in module-level router; Router is created at import time but connects only when tests run |
| tests/local_testing/test_completion.py | URL swap for test_lm_studio_completion; straightforward |
Reviews (4): Last reviewed commit: "fix(tests): keep fake OpenAI mock alive ..." | Re-trigger Greptile
|
Generated by Claude Code |
|
bugbot run Generated by Claude Code |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: xdist worker kills shared mock
- Removed the per-worker atexit hook and spawned the mock with start_new_session=True so the subprocess detaches from the spawning xdist worker and survives until the host or container exits, while the existing /health reuse path covers subsequent runs.
You can send follow-ups to the cloud agent here.
ensure_fake_openai_endpoint registered atexit on the worker that spawned the subprocess, so under -n 4 the first worker to drain its queue would terminate the shared mock while siblings were still hitting it. Detach the child via start_new_session and drop the per-worker teardown; reuse on /health handles re-runs and CI containers clean up themselves
b6d30ed to
d03f857
Compare
|
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 d03f857. Configure here.
…ndpoint (BerriAI#30900) * test: point router/completion/triton tests at the local fake OpenAI endpoint The shared Railway-hosted mock (exampleopenaiendpoint-production.up.railway.app) takes down unrelated CI jobs whenever it is unreachable. BerriAI#30695 moved the mounted proxy configs onto a job-local fake server but left these in-Python api_base literals pointing at the dead host, so litellm_router_testing, local_testing_part1, local_testing_part2 and llm_translation_testing still fail with a 404 "Application not found" when Railway is down Resolve the api_base from FAKE_OPENAI_API_BASE (default http://127.0.0.1:8190) through a shared helper, auto-start the canned server from the local_testing and llm_translation conftests when nothing is already serving, and extend the server with a Triton embeddings route and a slow-endpoint delay so the triton and latency-timeout tests run fully offline. The deliberately broken fallback URL is left as-is so fallback handling still has a failing upstream * fix: ignore non-loopback FAKE_OPENAI_API_BASE so the local mock is used in CI * fix: drop 0.0.0.0 from loopback hosts, an unreliable client connect target * fix(tests): keep fake OpenAI mock alive across xdist workers ensure_fake_openai_endpoint registered atexit on the worker that spawned the subprocess, so under -n 4 the first worker to drain its queue would terminate the shared mock while siblings were still hitting it. Detach the child via start_new_session and drop the per-worker teardown; reuse on /health handles re-runs and CI containers clean up themselves
Relevant issues
Follow-up to #30695, which replaced the shared Railway-hosted fake OpenAI mock (
exampleopenaiendpoint-production.up.railway.app) with a job-local server for the proxy E2E jobs. That PR migrated the mounted YAML configs but left theapi_baseliterals that several unit/integration tests hardcode in Python still pointing at the hosted host. When Railway is unreachable those tests fail with404 "Application not found", which is exactly what reddenedlitellm_router_testing,local_testing_part1,local_testing_part2andllm_translation_testingon #30894 even though that PR only rebuilds UI artifactsLinear ticket
N/A
Pre-Submission checklist
make test-unit@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewCI (LiteLLM team)
Branch creation CI run
Link:
CI run for the last commit
Link:
Merge / cherry-pick CI run
Links:
Screenshots / Proof of Fix
The fix is that the previously-failing tests no longer touch any external host. With nothing pre-started, the test session brings up the local server itself (the
local_testingandllm_translationconftests callensure_fake_openai_endpoint, which reuses a CI-started server when one is already healthy). The two behaviors the migrated tests depend on are the Triton embeddings shape and theslow-endpointdelay; here is the local server serving both, plus the regular chat path, with Railway entirely out of the loop:The end-to-end proof is the branch CI run:
litellm_router_testing,local_testing_part1,local_testing_part2andllm_translation_testingshould go green with the Railway host never contactedType
🐛 Bug Fix
✅ Test
Changes
Adds
tests/fake_openai_endpoint.py, a small shared helper that exposesFAKE_OPENAI_API_BASE(resolved from the env var, defaulthttp://127.0.0.1:8190) and an idempotentensure_fake_openai_endpoint()that reuses an already-healthy server (via its/healthcheck) or spawnstests/_fake_openai_endpoint_server.pydetached for the session. It deliberately registers no per-process teardown: under pytest-xdist the spawn happens in whichever worker wins the race and workers exit independently, so anatexithook would tear the shared server down while siblings are still calling it. CI containers are ephemeral and a cold local re-run just reuses the still-healthy server, so the leak is harmless. Thelocal_testingandllm_translationconftests start it via a session-scoped autouse fixture, so those jobs no longer need the endpoint pre-wired in CI and a cold local run works the same as CIReplaces the hardcoded Railway
api_baseliterals in the eight tests that actually made live calls (test_triton,test_router,test_router_custom_routing,test_router_fallback_handlers,test_router_fallbacks,test_secret_detect_hook,test_lowest_latency_routing,test_completion) withFAKE_OPENAI_API_BASE. The respx/mock/cassette-backed references in other files are left alone since they never hit the network. The deliberately broken...railway.appzzzzzfallback URL is also left as-is so fallback handling still has a failing upstreamExtends the canned server with a
/triton/embeddingsroute returning the Triton output shape the embedding transform expects, and aslow-endpointmodel that sleeps past the latency test's 1s timeout so the timeout/penalty path runs deterministically offline. Both are inert for the existing proxy E2E jobs, which never send thoseAdds
tests/local_testing/test_fake_openai_endpoint.pycovering the chat shape, the Triton route, the slow-endpoint delay, and a guard that fails if any migrated file reintroduces a liverailway.appapi_baseNote
Low Risk
Test-only infrastructure and URL swaps; no production LiteLLM runtime paths change.
Overview
CI and local runs no longer depend on the shared Railway fake OpenAI host. Router, completion, Triton, and related tests that used to hardcode
exampleopenaiendpoint-production.up.railway.appnow pointapi_baseatFAKE_OPENAI_API_BASEvia a newtests/fake_openai_endpoint.pyhelper.That helper resolves the base URL (loopback-only if
FAKE_OPENAI_API_BASEis set; remote env values are ignored so CI does not try to bind locally to a hosted URL), health-checks/health, and spawns_fake_openai_endpoint_server.pywhen needed. The subprocess is detached and not torn down on interpreter exit so pytest-xdist workers do not kill a shared mock mid-session.local_testingandllm_translationconftests start it with a session-scoped autouse fixture.The canned server gains
slow-endpoint(3s delay for latency/timeout tests) andPOST /triton/embeddingswith the embedding shape Triton tests expect.test_fake_openai_endpoint.pycovers those behaviors and fails if migrated files reintroduce liverailway.appURLs. VCR is told to skip that file since it hits loopback only.Reviewed by Cursor Bugbot for commit d03f857. Bugbot is set up for automated code reviews on this repo. Configure here.