litellm/tests/e2e/management
devin-ai-integration[bot] f285229b51
fix(proxy): delete large teams without per-member transaction fan-out (#42998)
* fix(proxy): delete large teams without per-member transaction fan-out

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): evict email-only member caches and reset team members metric on delete

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): keep new delete-team literals within the LIT002 ceiling

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): resolve deleted-team member ids before the locked delete

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(proxy): resolve email-only deleted-team members with one case-insensitive lookup

`_deleted_team_member_user_ids` looked each email-only roster entry up with its own
`find_users_by_email` call inside an unbounded `asyncio.gather`: one exact-match query
per email, so a large roster fanned out against the pool again and a roster email that
differed in case from its user row was missed. Add `UserRepository.find_by_emails`, a
single case-insensitive `in` query, and call it once before the locked delete.
`management_helpers/utils.py` goes back to its main-branch shape since the single-email
helper no longer needs exporting.

* fix(repositories): slice find_by_emails into bounded IN statements

The unbounded-IN lint flagged the case-insensitive email lookup added for
/team/delete cache eviction. chunked_in.find_many_in cannot carry Prisma's
insensitive mode, so the repository slices the deduplicated list into
IN_LIST_CHUNK_SIZE statements itself and concatenates the pages. Empty input
still returns () without a query.

* fix(proxy): delete a team once when /team/delete repeats its id

The audit sent {"team_ids": [T, T]}: main answered 400 "User not found in
team" after deleting the keys and memberships and writing two tombstones,
leaving the team row behind; this branch answered 200 but still wrote the
tombstone, audit row and eviction twice. DeleteTeamRequest now collapses
repeated ids in order, so every later step sees each team once and the
response lists each deleted team once.

* test(integration): audit cells for /team/delete on large, legacy and concurrent teams

Thirty-eight deterministic cells in tests/integration/management/ (the CircleCI
integration-management group) covering the /team/delete happy, sad, edge and chaos rows:
250 members against a pool limit of five on two workers, the advisory-lock wait, email-only
legacy roster entries in every casing, member and team cache eviction on both proxies for
every client and endpoint, the Prometheus gauge, audit rows, malformed and duplicate input,
the route gate, and a worker kill, a Redis outage and a proxy restart mid-burst.

Every cell runs against the real proxy, Postgres and Redis with the scripted upstream; no
component is mocked. On the merge base the rows this fix changes are red (P2028 on the
250-member team, two lock waiters, case-mismatched email lookups, duplicate ids, orphaned
LiteLLM_UserTable.teams references under a concurrent burst); on the tip every cell is green
twice with identical selections.

Two pre-existing behaviours are pinned as observed rather than fixed here: a roster entry with
neither user_id nor user_email answers 500, and the LiteLLM_DeletedTeamTable row is committed
before the locked transaction, so a delete that dies in between leaves a tombstone for a live
team and the retry adds a second.

* test(integration): pin each chaos outage to a live /team/delete

The three chaos cells applied the outage once three deletes had answered, which on a fast
run let the whole burst finish before the worker kill, Redis stop or SIGTERM landed, so the
cells passed without exercising the failure. Each cell now holds the first team's advisory
lock from a test-owned transaction, waits until that team's delete is queued behind it in
Postgres with its request unanswered, applies the outage, and only then releases the lock,
so an in-flight delete meets the failure on every run and both legs. The pinned team's
outcome and the number of deletes answered before the outage are recorded as junit
properties (pinned_delete, answered_before_outage).

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: ryan-crabbe-berri <ryan@berri.ai>
2026-09-30 13:49:18 -07:00
..
conftest.py test: bind management E2E callers and isolate JWT actors 2026-09-12 13:29:04 -07:00
jwt_actors.py test: enforce isolated actors and stop OIDC process groups 2026-09-12 13:49:49 -07:00
management_client.py fix(proxy): delete large teams without per-member transaction fan-out (#42998) 2026-09-30 13:49:18 -07:00
test_budget_customer_user_org_e2e.py test(e2e): un-skip the per-model budget update case 2026-08-26 18:09:10 -07:00
test_config_misc_endpoints_e2e.py test(e2e): stop the config suite locking itself out of the shared proxy 2026-09-19 12:51:54 -07:00
test_jwt_management_e2e.py test: enforce isolated actors and stop OIDC process groups 2026-09-12 13:49:49 -07:00
test_key_lifecycle_e2e.py test(e2e): read a deleted key back as deleted, not as a 404 2026-09-17 02:38:27 +00:00
test_key_management_e2e.py test: expect 422 for budget refusals in unification, e2e and integration suites 2026-09-20 06:33:57 +00:00
test_management_e2e.py fix(proxy): delete large teams without per-member transaction fan-out (#42998) 2026-09-30 13:49:18 -07:00
test_mcp_lifecycle_e2e.py fix(mcp): honor an explicit null on toolset update, cover MCP lifecycle e2e (#40022) 2026-09-08 22:50:13 -07:00
test_model_tag_accessgroup_e2e.py test(model_management): drive /model/block and /model/unblock through response serialization 2026-08-29 21:39:07 -07:00
test_model_test_connection_e2e.py test(e2e): retry timeout-shaped Mantle test_connection probes 2026-08-25 11:05:38 -07:00
test_team_management_e2e.py fix(proxy): refuse a team admin's budget write when the budget changed mid-request 2026-09-16 18:11:53 -07:00