litellm/tests/llm_translation
yuneng-jiang cddc7cde97
test: fix stale and flaky tests across CircleCI, GHA and Buildkite (#45530)
* test(integration): poll the partition lock witness off the event loop

The witness poll ran a blocking psycopg connect and query on the test's event loop, so the partition DDL task only progressed during the 20ms sleeps and missed the 3s deadline on loaded runners. Polling through asyncio.to_thread lets the DDL reach the held lock concurrently, and the deadline is 10s since it only bounds how long the DDL takes to start waiting

* test(e2e): retry the reasoning turn until the model emits a reasoning item

Whether gpt-5.4-mini emits a reasoning item next to a forced function call is up to the model, and it skipped it on four scheduled runs while a same-SHA rerun passed. The first turn now retries up to three times before the unchanged reasoning-item assertion

* test(e2e): retry a Bedrock Converse model once when it reports no cache tokens

Opus on Bedrock Converse reported zero cache tokens on half of the scheduled runs while a same-SHA rerun passed. A model that comes back uncached is asked once more inside the 5 minute window, and the non-zero cache token assertion is unchanged

* test(e2e): poll until a deleted stored response stops being retrievable

Azure kept serving a just-deleted streamed response for a moment, so a single retrieve did not raise. Both delete tests now poll retrieve until it returns an error and still require a 4xx

* test(e2e): give the Together prompt cache five primed attempts

Together documents its prefix cache as best-effort, and three primed attempts came back with zero cached tokens once while a same-SHA rerun passed

* test(e2e): allow 30s for the idle RSS reading at session start

A loaded router replica took longer than 10s to answer the session-start memory read, which pytest reruns cannot recover. The RSS budget assertion is unchanged

* test(e2e): scope the MCP submission check to its own card

The register call timed out at 15s on a loaded stack and leaked a submitted server, so the retries matched two "3 passing, 1 failing" cards. Registration gets 60s and the check reads only the submitted server's card

* test(router): wait for the primary success record before counting it

The shadow fan-out test waited only for the two shadow success events and then asserted exactly one primary success, which the logging worker sometimes had not delivered yet. It needed a rerun on 5 of 59 main runs

* test(proxy): give the spend-log cleanup run a 1s budget

A 0.25s budget could expire before the first batch on a loaded xdist worker, leaving rows_deleted at 0. One second still stops the 50-batch, 5-second loop on the deadline, which is what the test proves

* test(autorouter): release the slow token count at 2.05s instead of 2.3s

The count only has to finish after a quarter of the 8s worker budget, and the planner gives it 3s, so releasing at 2.3s left 0.7s of slack that a loaded runner used up. 2.05s is still past the quarter mark with almost 1s of slack

* test(xai): run the reasoning-effort tests on grok-4.6 with a prompt that needs reasoning

grok-4.7 now returns reasoning tokens without any reasoning text, so reasoning_content was never set and both tests failed on every scheduled run. Called directly, grok-4.6 returned reasoning text 6 of 6 times on a step-by-step arithmetic prompt but only some of the time on a bare greeting

* test(integration): give the two worker-kill chaos tests the owned-proxy time budget

Each test spends about 50s on the burst and then up to graceful_stop_seconds() stopping its owned proxy, which overran the 90s default pytest timeout on loaded runners. They now use the same 2 * graceful_stop_seconds() + 120 budget as other owned-proxy tests

* test(integration): compare regional image responses without their created timestamp

Two identical generations that straddle a second boundary differ only in created, which failed the byte-for-byte comparison. Every other field and both spend rows are still compared

* test(integration): count only the S3 logger's flush task

The set of asyncio tasks created while the logger starts also picked up client close finalizers left by earlier tests, so the count ranged from 1 to 8. The test now counts the periodic_flush task it owns and cancels

* test(integration): send guardrail timeout probes eight at a time

All 44 probes went at once to a two-worker proxy, so on a loaded runner some guardrails used their whole 1s timeout before their request left the proxy, and the sink never saw them. A different set of providers failed on each run. Eight in flight still overlaps the waits

* test(integration): count a killed Arize chaos worker as gone once it is a zombie

psutil reports an unreaped zombie as still running, so the 10s death check failed whenever the supervisor was slow to reap the SIGKILLed worker, and the stop then overran the 90s default timeout. The test now accepts a zombie or a missing process and has the owned-proxy time budget

* test(integration): send the Typesafe connection test its real model and endpoint

The test passed the proxy alias as litellm_params.model, and /health/test_connection lays the request over the stored deployment, so the alias replaced the real typesafe/ model and the check failed with "LLM Provider NOT provided" on every run since it landed in #45481. It now sends the provider model, api_base and api_key directly

* test(integration): keep DB-stored models out of the usage-routing Redis read test

The owned proxy inherited store_model_in_db and the job's shared database, so a model another test left behind joined the router and added its cooldown key to the MGET the test compares exactly. Reproduced locally with one /model/new model present (3 failed), and green with model loading from the database turned off

* test(vertex_ai): prove the batch upload streams by laziness instead of peak memory

The two tracemalloc ratio tests flaked on unrelated PRs because peak memory on a shared xdist worker includes other threads' allocations and garbage from earlier tests. They are replaced by deterministic checks of the same property: the upload stream parses and maps a row only when it is pulled, so a body whose tail is not JSON yields its valid rows first, and a Path source reflects a row rewritten on disk after the upload started. Making the parse, the output, or the file read eager fails these tests

* test(integration): keep the alias test_connection call as a known bug

* test: type the counting mapper and the Bedrock rerun helper

* test: annotate the new test locals as Final and build them as tuples

* test(vertex_ai): prove pull-driven transforms with the garbage tail alone
2026-10-09 11:40:14 -07:00
..
fixtures test fix 2025-10-16 18:00:46 -07:00
interactions test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
realtime test: delete 34 legacy tests already covered by e2e (#45340) 2026-10-08 09:43:56 -07:00
reasoning_effort_grid test(reasoning-effort-grid): bump the cell count for the four new Fable 5.1 cells 2026-09-01 18:28:33 +00:00
test-skill [Feat] New API - Claude Skills API (Anthropic) (#17042) 2025-11-24 15:01:40 -08:00
test_skills_data Remove Apache 2 license from SKILL.md (#22322) 2026-02-27 19:33:55 -08:00
base_audio_transcription_unit_tests.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
base_embedding_unit_tests.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
base_llm_unit_tests.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
base_rerank_unit_tests.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
conftest.py test(vcr): guard leaked cassette patches and make injected-transport embedding tests immune (#42542) 2026-09-22 14:20:18 -07:00
databricks_config.template.txt test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
dog.wav (feat) Support audio param in responses streaming (#6312) 2024-10-18 19:16:14 +05:30
duck.png fix vertex ai multimodal embedding translation (#9471) 2025-03-24 23:23:28 -07:00
gettysburg.wav Litellm dev 12 25 2025 p2 (#7420) 2024-12-25 18:35:34 -08:00
guinea.png fix vertex ai multimodal embedding translation (#9471) 2025-03-24 23:23:28 -07:00
log.xt Litellm dev 04 05 2025 p2 (#9774) 2025-04-07 21:02:52 -07:00
Readme.md test: delete 34 legacy tests already covered by e2e (#45340) 2026-10-08 09:43:56 -07:00
test_a2a.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_anthropic_completion.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_azure_agents.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_azure_ai.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_azure_o_series.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_azure_openai.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_bedrock_agentcore.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_bedrock_completion.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_bedrock_embedding.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_bedrock_gpt_oss.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_bedrock_invoke_tests.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_bedrock_llama.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_bedrock_moonshot.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_bedrock_nova_json.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_cohere.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_cometapi_chat_transformation.py test: move whole-unit legacy test files into tests/unit and delete dead skips (#44807) 2026-10-07 05:02:28 +00:00
test_compression.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_databricks.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_deepgram.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_deepseek_completion.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_elevenlabs.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_evals_api.py test: delete 73 legacy tests covered by e2e, unable to fail, or dead in CI (#45195) 2026-10-07 17:11:36 -07:00
test_fireworks_ai_translation.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_gemini.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_gpt4o_audio.py refactor: expose core private helpers under public names (#44871) 2026-10-07 00:05:27 +00:00
test_groq.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_hosted_vllm_embedding_e2e.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_huggingface_chat_completion.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_jina_ai.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_json_providers.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_lambda_ai.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_mistral_api.py test: delete 73 legacy tests covered by e2e, unable to fail, or dead in CI (#45195) 2026-10-07 17:11:36 -07:00
test_mistral_audio_transcription_transformation.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_openai.py test: delete 73 legacy tests covered by e2e, unable to fail, or dead in CI (#45195) 2026-10-07 17:11:36 -07:00
test_openai_o1.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_openrouter.py refactor: expose core private helpers under public names (#44871) 2026-10-07 00:05:27 +00:00
test_optional_params.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_ovhcloud_audio_transcription_transformation.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_ovhcloud_chat_transformation.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_prompt_caching.py test: drop the cwd-relative sys.path.insert calls from the test suite (#37802) 2026-08-22 09:25:58 -07:00
test_prompt_factory.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_rerank.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_router_llm_translation_tests.py test: delete 73 legacy tests covered by e2e, unable to fail, or dead in CI (#45195) 2026-10-07 17:11:36 -07:00
test_skills_api.py refactor: expose core private helpers under public names (#44871) 2026-10-07 00:05:27 +00:00
test_text_completion.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_together_ai.py test: make 38 legacy live base-class translation tests offline (#45351) 2026-10-08 23:18:25 +00:00
test_triton.py test: move offline logging, secret manager and provider tests from legacy dirs into tests/unit (#45554) 2026-10-09 09:48:10 -07:00
test_v0.py test: move the unit half of 126 mixed legacy files into tests/unit (#45090) 2026-10-07 14:07:43 -07:00
test_vertex_ai_image_generation_transformation.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00
test_xai.py test: fix stale and flaky tests across CircleCI, GHA and Buildkite (#45530) 2026-10-09 11:40:14 -07:00
test_xiaomi_mimo.py test: finish the non-proxy half of tests/test_litellm (#43281) 2026-09-25 22:43:41 -07:00

Unit tests for individual LLM providers.

Name of the test file is the name of the LLM provider - e.g. test_openai.py is for OpenAI.

Redis-backed VCR cache

Every test in this directory is auto-decorated with @pytest.mark.vcr (via conftest.py). The first time a test runs we hit the live provider and record the HTTP exchange into Redis under litellm:vcr:cassette:<test_id>. Every subsequent run within 24h replays from Redis without touching the network. The 24h TTL means each new day's first run records again, so upstream API drift surfaces within a day.

The persister, header scrubbing, and 2xx-only filtering are defined in tests/_vcr_redis_persister.py. Files that already use respx (which patches the same httpx transport vcrpy does) are excluded from the auto-marker — see _RESPX_CONFLICTING_FILES in conftest.py.

Requests to localhost, 127.0.0.1, or 0.0.0.0 are never recorded or replayed (ignore_localhost in vcr_config_dict()): a server the test process starts itself on an ephemeral port is not a provider, and a cassette entry for it would replay against whichever later test lands on that port

The same VCR cache is used by other test directories that exercise live provider APIs. The reusable conftest plumbing lives in tests/_vcr_conftest_common.py and is wired into:

  • tests/llm_translation/
  • tests/audio_tests/
  • tests/batches_tests/
  • tests/guardrails_tests/
  • tests/image_gen_tests/
  • tests/litellm_utils_tests/
  • tests/local_testing/ (covers local_testing_part1, local_testing_part2, litellm_router_testing, litellm_assistants_api_testing, langfuse_logging_unit_tests)
  • tests/logging_callback_tests/
  • tests/pass_through_unit_tests/
  • tests/router_unit_tests/
  • tests/unified_google_tests/

Test directories that run LiteLLM proxy in Docker (e.g. build_and_test, proxy_logging_guardrails_model_info_tests, proxy_store_model_in_db_tests) are intentionally not included: VCR.py patches the in-process httpx transport, so it cannot intercept the LLM calls that originate inside the Docker container.

Required environment

CASSETTE_REDIS_URL — separate Redis instance from the application Redis (REDIS_URL/REDIS_HOST) so test cassettes are not flushed by proxy tests. Provider credentials (ANTHROPIC_API_KEY, OPENAI_API_KEY, AWS_*, etc.) are needed only on cache-miss (the daily re-record), not on replay.

Flushing the cache

When you want the next run to re-record immediately instead of waiting for the 24h TTL:

make test-llm-translation-flush-vcr-cache

Disabling VCR

Skip the cache entirely (every call goes live, no recording):

LITELLM_VCR_DISABLE=1 uv run pytest tests/llm_translation/test_<file>.py