[Fix] Deflake spend tracking tests - #26349
Conversation
[Infra] Promote interal staging to main
Two independent deflakes: 1. test_ui_view_spend_logs_unauthorized (unit) was returning 400 instead of 401/403 when earlier tests in the file left proxy-auth globals (prisma_client, master_key, user_custom_auth, general_settings, user_api_key_cache) in a state that let invalid tokens pass auth and fall through to the endpoint's own start_date/end_date validation. Add an autouse fixture that pins those globals to their import-time defaults for every test in the file. Harden the assertion to include response body so future flakes are diagnosable. 2. test_basic_spend_accuracy (CI job proxy_spend_accuracy_tests) depends on the Redis transaction buffer flushing spend to Postgres. The buffer uses a single global pod-lock key (cronjob_lock:db_spend_update_job) and a single global buffer list key. Pointing the proxy at the shared remote Redis means concurrent CI pipelines contend for the same lock and can drain each other's buffer into the wrong database. Add a start_redis reusable command that boots a per-job redis:7-alpine container (digest-pinned), and switch proxy_spend_accuracy_tests to REDIS_HOST=host.docker.internal:6379 so lock and buffer state are isolated per CI run.
Low: CI and test-only changesThis PR deflakes spend tracking tests by spinning up a job-local Redis container in CI instead of sharing a remote one, and adds a test fixture to reset proxy auth globals between tests. Both changes are scoped entirely to CI configuration and test files with no impact on production runtime code. Status: 0 open Posted by Veria AI · 2026-04-23T21:22:02.432Z |
Greptile SummaryThis PR deflakes two spend-tracking tests: it pins proxy auth globals ( Confidence Score: 5/5Safe to merge — changes are test/CI infrastructure only with no production code modifications. Both fixes are well-reasoned and narrowly scoped: the autouse fixture correctly uses monkeypatch (auto-teardown) to reset proxy globals and directly clears the in-memory cache dict at test start; the CI fix uses a digest-pinned local Redis container and guards cleanup with No files require special attention.
|
| Filename | Overview |
|---|---|
| .circleci/config.yml | Adds a reusable start_redis command (digest-pinned image) and switches proxy_spend_accuracy_tests to a job-local Redis, eliminating cross-pipeline contention on the global pod-lock and buffer keys; cleanup step now guards with when: always. |
| tests/test_litellm/proxy/spend_tracking/test_spend_management_endpoints.py | Adds an autouse fixture that resets proxy auth globals and the in-memory token cache before every test, preventing global-state leakage between tests; assertion messages now include response.text for clearer failure output. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
subgraph CI Job: proxy_spend_accuracy_tests
A[checkout] --> B[start_postgres\npostgres:14 on :5432]
B --> C[start_redis\nredis:7-alpine on :6379]
C --> D[docker run my-app\nREDIS_HOST=host.docker.internal\nREDIS_PORT=6379]
D --> E[wait_for_service :4000]
E --> F[pytest spend_tracking_tests]
F --> G{when: always}
G --> H[docker stop/rm my-app\ndocker stop/rm redis-cache]
end
subgraph Before: shared remote Redis
X[Pipeline A] -->|cronjob_lock| Z[(Remote Redis)]
Y[Pipeline B] -->|cronjob_lock| Z
Z -->|contention / wrong DB flush| ERR[Flaky test]
end
subgraph After: per-job local Redis
P1[Pipeline A] --> R1[(Local Redis A)]
P2[Pipeline B] --> R2[(Local Redis B)]
R1 --> OK1[Isolated flush]
R2 --> OK2[Isolated flush]
end
Reviews (3): Last reviewed commit: "[Fix] Drop orphan teardown step from Gre..." | Re-trigger Greptile
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
| - run: | ||
| name: Stop and remove first container |
There was a problem hiding this comment.
Dangling
run step with no command
The first "Stop and remove first container" step at line 1845 has only a name key and no command. CircleCI validates that every run step includes a command; this config will fail validation (or produce a confusing empty-step error at runtime). The original step should have been modified in-place — with when: always and the updated commands — rather than leaving an empty copy behind and adding a second step.
| - run: | |
| name: Stop and remove first container | |
| # Clean up first container | |
| - run: | |
| name: Stop and remove first container | |
| when: always | |
| command: | | |
| docker stop my-app | |
| docker rm my-app | |
| docker stop redis-cache | |
| docker rm redis-cache |
Previous commit from greptile-apps added a new `when: always` teardown step without removing the prior `name:`-only step, leaving a `- run` block with no `command:` — CircleCI config validation rejects that. Collapse back to a single teardown step that runs on success and failure.
[Fix] Deflake spend tracking tests
Relevant issues
Summary
Two independent deflakes of spend tracking tests.
Fix
1.
test_ui_view_spend_logs_unauthorizedwas intermittently returning 400 instead of 401/403 for a request with an invalid bearer token. Earlier tests in the same file could leave proxy-auth globals (prisma_client,master_key,user_custom_auth,general_settings, cached tokens) in a state where an invalid token slipped pastuser_api_key_authand reached the endpoint's ownstart_date/end_datevalidation. Added an autouse fixture that pins those globals to their import-time defaults for every test in the file, and tightened the assertion to include the response body so any future regression surfaces the actual cause instead of a bare status code.2.
test_basic_spend_accuracy(CI jobproxy_spend_accuracy_tests) depends on the Redis transaction buffer flushing spend from Redis to Postgres. The buffer uses a single global pod-lock key (cronjob_lock:db_spend_update_job) and a single global buffer list key (litellm_spend_update_buffer). The CI job was pointed at the shared remote Redis via$REDIS_HOST, so concurrent CI pipelines would contend for the same lock and could LPOP one another's spend entries and commit them to the wrong Postgres instance. Added a reusablestart_redisCircleCI command that boots a per-jobredis:7-alpinecontainer (digest-pinned) and switchedproxy_spend_accuracy_teststoREDIS_HOST=host.docker.internal:6379so lock and buffer state are isolated per CI run. This keeps the Redis transaction buffer code path under test while eliminating cross-pipeline contention.Testing
tests/test_litellm/proxy/spend_tracking/test_spend_management_endpoints.pythree times in a row locally — 61 passed each run.test_basic_spend_accuracycan only be validated on CircleCI; the structural fix (per-job Redis) is observable viadocker logs redis-cacheand the usual job flow.Type
🐛 Bug Fix
🚄 Infrastructure
✅ Test
Screenshots