Repository navigation
test: fix stale and flaky tests across CircleCI, GHA and Buildkite - #45530
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
fb8e988 to
724d304
Compare
724d304 to
261d488
Compare
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
… 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
…he 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
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
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
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
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
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
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
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
…hat 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
…xy 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
…ated 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
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
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
…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
…nd 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
…is 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
…f 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
261d488 to
3b9cc14
Compare
|
|
@greptileai please re-review: the alias call is a BUG skip again, the new helpers are typed, and the memory thread has a reply |
|
@greptileai please re-review: every new local added by this PR is now Final, and the new list values are tuples |
|
@greptileai please re-review: the counting mapper and its mutable list are gone, and no new test code mutates state now |
TLDR
Problem this solves:
How it solves it:
Which tests, and why they flaked
Each entry names the test, the evidence that it was flaky or broken rather than a product bug, and the fix
CircleCI
tests/integration/database/test_partition_transactions.py::test_real_partition_ddl_survives_witnessed_lock_and_is_idempotentasyncio.to_thread, deadline 10s. Passes against a local Postgrestests/llm_translation/test_xai.py::TestXAIReasoningEffort(2 tests)grok-4.7now returns reasoning tokens but no reasoning text, soreasoning_contentis never setgrok-4.6with a step-by-step arithmetic prompt: 6 of 6 direct calls returned reasoning text, a bare "Hello" only some of the time. Both tests passed 4 times livetests/integration/observability/test_passthrough_upstream_error_chaos.py::test_passthrough_worker_sigkill_leaves_sibling_serving_and_loggingandtests/integration/routing/test_audit_any_sweep_chaos.py::test_proxy_survives_worker_kill_mid_burstgraceful_stop_seconds()(70s) of stop does not fit in 90s. They now get2 * graceful_stop_seconds() + 120, like other owned-proxy teststests/integration/spend/test_vertex_image_regional_uplift.py::test_identical_regional_generations_each_bill_the_uplift_oncecreated(1791533128 vs 1791533129), a second-boundary racecreated; both spend rows are still assertedtests/integration/providers/test_s3_wire.py::test_s3_sync_and_async_uploads_pass_independent_wire_verificationCustomBatchLogger.periodic_flushtask the test owns. Passes locally twicetests/integration/observability/test_guardrail_timeout_all_providers.py::test_litellm_params_timeout_bounds_outbound_calltests/integration/observability/test_arize_otel_v2_openinference_chaos.py::test_arize_otel_v2_f3_one_proxy_worker_can_dietests/integration/providers/test_decisions_wire.py::test_test_connection_evaluation_mode_uses_typesafe_decisions_pathlitellm_params.model, which replaced the realtypesafe/model, so the check failed with "LLM Provider NOT provided"api_baseandapi_keydirectly. Passes locallytests/integration/routing/test_usage_based_routing_redis_reads.py::test_proxy_usage_routing_reads_cooldown_tpm_then_rpm_from_redis(3 params)store_model_in_dband the shared database, so a model left by another test added its cooldown key to the exact MGET comparison/model/newmodel present (3 failed). With model loading from the database off: 3 passedGHA unit
tests/unit/test_router_silent_experiment.py::test_multiple_shadow_targets_fan_out_asynctests/unit/proxy/test_spend_log_cleanup.py::test_run_budget_stops_the_loop_and_leaves_the_backlog_for_the_next_runrows_deleted=0because the 0.25s budget expired before the first batchtests/unit/proxy/test_proxy_utils.py::test_during_call_hook_parallel_executiontests/unit/llms/vertex_ai/files/test_vertex_ai_files_streaming.py, the two peak-memory teststests/unit/proxy/hooks/test_autorouter_baseline_cache.py::test_native_count_finishing_after_quarter_worker_budget_keeps_plan_and_spendBuildkite e2e
tests/e2e/llm_translation/test_responses_e2e.py::TestResponsesOpenAIHostedFeatures::test_reasoning_items_replay_into_structured_output_after_tool_calltests/e2e/claude_code/prompt_caching_5m/test_bedrock_converse.py::test_prompt_caching_5m_bedrock_conversetests/e2e/llm_translation/test_responses_retrieve_e2e.py, both delete teststests/e2e/llm_translation/test_together_ai_e2e.py::TestTogetherChatCompletions::test_cache_read_tokens_bill_at_the_cache_read_ratetests/e2e/router/test_reliability_memory_e2e.py::TestReliabilityMemory::test_workers_idle_under_rss_budget_before_traffictests/e2e/ui/tests/mcp/mcpSubmissionRules.spec.ts"Submission Rules panel shows saved rules..."Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/unit/<your_test_file>.py -v. Leave the suites (make test-unit-*,make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
The proof is CI itself: the same jobs before and after, with every CircleCI job forced to run on this branch by the temporary
ci:commitBefore (145d382 and fb8e988)
5ad9cbd6at 145d382 and this PR's first full rundb09a739at fb8e988 had every CircleCI test above failing in at least one of themlitellm-e2ebuilds 380 to 387 had the six e2e failures above, each with a passing rerun at the same SHA inlitellm-e2e-pruniton main needed reruns or failed for the three main-side unit tests above, and the other two failed on unrelated PRsAfter (724d304, plus 261d488 for the Vertex unit tests)
8ee35d0cat 724d304: every CircleCI test fixed above passed, includingllm_translation_testing(xAI) andintegration-database(partition)38 passedfor the whole file locally, and three eager variants of the stream code each fail themType
✅ Test
🚄 Infrastructure
Caveats (if any)
High
ci: temporarily run main-only CircleCI jobs on this branchcommit must be dropped before mergetest_h5_...)/v1/messagescache hits now returnx-litellm-cache-keysince refactor: expose public hidden_params accessors #44668 (test_arize_otel_v2_a_cache[messages])/anthropic/v1/messagesthrough a custom base logs a uuid id and zero usage (test_native_passthrough_spend_rows_...)Medium
anthropicFederationCredential.spec.ts(3 tests), probably from feat(ui): configure OpenAI workload identity federation from the LLM Credentials and Add Model forms #45528test_user_updates_wedged_coordination_redistest_anthropic_messages_pre_content_retry_wiretest_logging_standard_payload_llm_headers[True]Low
grok-4.6returning reasoning text, as measured on 2026-10-09QA runbook
openai/gpt-5.4-mini, theget_todaytool forced,reasoning: {"effort": "medium"}and a JSON schema text format; retry until the output has a reasoning item (at most 3 times)function_call_outputof2025-01-15completedandtodayin the parsed output to contain2025-01-15cache_creation_input_tokensorcache_read_input_tokensabove 0, asking an uncached model once morecached_tokensis above 0Final Attestation