mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-19 00:01:29 +00:00
fix(team): preserve bulk update failures
This commit is contained in:
parent
639cba2922
commit
db9decaed7
2 changed files with 37 additions and 15 deletions
|
|
@ -3072,6 +3072,9 @@ async def bulk_update_team_members(
|
|||
successful_updates.append(response)
|
||||
except HTTPException as exc:
|
||||
failed_updates.append(FailedTeamMemberUpdate(user_id=user_id, failed_reason=str(exc.detail)))
|
||||
except Exception as exc:
|
||||
verbose_proxy_logger.exception("Failed to bulk update team member %s in team %s", user_id, data.team_id)
|
||||
failed_updates.append(FailedTeamMemberUpdate(user_id=user_id, failed_reason=str(exc)))
|
||||
|
||||
return BulkTeamMemberUpdateResponse(
|
||||
team_id=data.team_id,
|
||||
|
|
|
|||
|
|
@ -86,9 +86,7 @@ def happy_path_upsert(monkeypatch):
|
|||
AsyncMock(
|
||||
return_value={
|
||||
"team_info": team_row,
|
||||
"team_memberships": [
|
||||
types.SimpleNamespace(user_id="user-1", budget_id="bud-1")
|
||||
],
|
||||
"team_memberships": [types.SimpleNamespace(user_id="user-1", budget_id="bud-1")],
|
||||
}
|
||||
),
|
||||
)
|
||||
|
|
@ -98,9 +96,7 @@ def happy_path_upsert(monkeypatch):
|
|||
|
||||
|
||||
def _member_update_request(**overrides):
|
||||
data = TeamMemberUpdateRequest(
|
||||
team_id="team-1234", user_id="user-1", role="user", **overrides
|
||||
)
|
||||
data = TeamMemberUpdateRequest(team_id="team-1234", user_id="user-1", role="user", **overrides)
|
||||
request = Request({"type": "http", "method": "POST", "path": "/team/member_update"})
|
||||
auth = UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN.value, user_id="admin")
|
||||
return data, request, auth
|
||||
|
|
@ -110,9 +106,7 @@ def _member_update_request(**overrides):
|
|||
async def test_team_member_update_sends_provided_fields_as_patch(happy_path_upsert):
|
||||
"""Fields the request sets must reach _upsert_budget_and_membership as a
|
||||
budget patch, otherwise the member budget is never written/reset."""
|
||||
data, request, auth = _member_update_request(
|
||||
max_budget_in_team=10.0, budget_duration="30d"
|
||||
)
|
||||
data, request, auth = _member_update_request(max_budget_in_team=10.0, budget_duration="30d")
|
||||
|
||||
response = await team_member_update(data, request, auth)
|
||||
|
||||
|
|
@ -132,9 +126,7 @@ async def test_team_member_update_explicit_null_clears_field(happy_path_upsert):
|
|||
|
||||
await team_member_update(data, request, auth)
|
||||
|
||||
assert happy_path_upsert.await_args.kwargs["budget_patch"] == {
|
||||
"budget_duration": None
|
||||
}
|
||||
assert happy_path_upsert.await_args.kwargs["budget_patch"] == {"budget_duration": None}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
@ -158,9 +150,7 @@ async def test_team_member_update_omits_unset_fields_from_patch(happy_path_upser
|
|||
],
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_team_member_update_rejects_invalid_budget_duration(
|
||||
monkeypatch, bad_duration
|
||||
):
|
||||
async def test_team_member_update_rejects_invalid_budget_duration(monkeypatch, bad_duration):
|
||||
"""An invalid budget_duration must be rejected with a 400 before any DB
|
||||
write, so it can never be persisted and later break the budget reset job."""
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", object())
|
||||
|
|
@ -223,6 +213,35 @@ async def test_bulk_team_member_update_applies_patch_and_returns_member_failures
|
|||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_bulk_team_member_update_returns_unexpected_member_failure(monkeypatch):
|
||||
team_row = LiteLLM_TeamTable(
|
||||
team_id="team-1234",
|
||||
members_with_roles=[Member(user_id="user-1", role="user")],
|
||||
)
|
||||
prisma_client = MagicMock()
|
||||
prisma_client.db.litellm_teamtable.find_unique = AsyncMock(return_value=team_row)
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", prisma_client)
|
||||
monkeypatch.setattr(
|
||||
team_endpoints, "team_member_update", AsyncMock(side_effect=RuntimeError("database unavailable"))
|
||||
)
|
||||
|
||||
response = await bulk_update_team_members(
|
||||
data=BulkTeamMemberUpdateRequest(
|
||||
team_id="team-1234",
|
||||
user_ids=["user-1"],
|
||||
update_fields=TeamMemberBulkUpdateFields(tpm_limit=42),
|
||||
),
|
||||
http_request=Request({"type": "http", "method": "POST", "path": "/team/member/bulk_update"}),
|
||||
user_api_key_dict=UserAPIKeyAuth(user_role=LitellmUserRoles.PROXY_ADMIN.value, user_id="admin"),
|
||||
)
|
||||
|
||||
assert response.successful_updates == []
|
||||
assert response.failed_updates == [
|
||||
team_endpoints.FailedTeamMemberUpdate(user_id="user-1", failed_reason="database unavailable")
|
||||
]
|
||||
|
||||
|
||||
def test_bulk_team_member_update_requires_exactly_one_member_selector():
|
||||
with pytest.raises(ValueError, match="either user_ids or all_members_in_team"):
|
||||
BulkTeamMemberUpdateRequest(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue