litellm/tests/integration/_support/worker_readiness.py
devin-ai-integration[bot] 5261a2cc06
test(integration): cover responses endpoint contracts (#44733)
* test(integration): cover responses endpoint contracts

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

* test(integration): tighten responses contract tests per review

Isolate team-only response-id ownership with a same-user different-team key,
send every denial through the OpenAI SDK on all three aliases, make the
previous_response_id affinity check deterministic, assert the whole cancel
response, prove the Cursor stream text, -fast suffixes and include_obfuscation
strip, add SDK compact cases, restore router pre-call checks after the
affinity test, and inline the root-level responses_test_support helpers

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

* test(integration): wait for every proxy worker before routing to new deployments

Restore the cross-worker convergence wait dropped when the shared helper was
inlined, so the affinity and retrieve-routing tests cannot pass before the
alternative deployment is loaded on a multi-worker gateway

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

* test(integration): cover Responses ownership and wire contracts

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

* test(integration): address responses contract review

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

* test(integration): expect the provider model in the conversation passthrough body

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

* test(integration): expand responses endpoint contracts

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

* test(integration): restore streamed response retrieval

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

* test(integration): wait for proxy workers after deployment setup

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

* test(integration): track readiness per proxy worker

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

---------

Co-authored-by: mateo <mateo@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-14 06:59:15 +00:00

64 lines
2.7 KiB
Python

from __future__ import annotations
import time
from collections.abc import Iterator, Mapping
from itertools import accumulate
from types import MappingProxyType
from typing import Final
import httpx
from integration._support.client import Gateway, JSON_OBJECT, object_value
from litellm.constants import PROXY_CONFIG_RELOAD_INTERVAL_SECONDS
def _record_latest_readback(
latest_by_worker: Mapping[int, int],
observation: tuple[int, int],
) -> Mapping[int, int]:
worker_pid, count = observation
return MappingProxyType({**latest_by_worker, worker_pid: count})
def wait_for_worker_readiness(
gateway: Gateway,
group: str,
deployments: int,
workers: int,
) -> None:
deadline: Final = time.monotonic() + (30 if workers == 1 else PROXY_CONFIG_RELOAD_INTERVAL_SECONDS * 2 + 30)
headers: Final = {"Authorization": f"Bearer {gateway.key}"}
def readbacks() -> Iterator[tuple[int, int]]:
while time.monotonic() < deadline:
timeout: Final = deadline - time.monotonic()
with httpx.Client(
base_url=str(gateway.client.base_url),
timeout=timeout,
trust_env=False,
verify=False,
) as client:
debug_response: Final = client.get("/debug/memory/summary", headers=headers)
response: Final = client.get(
"/model/info",
headers=headers,
)
assert debug_response.status_code == 200, debug_response.text
assert response.status_code == 200, response.text
assert debug_response.extensions.get("network_stream") is not None
assert debug_response.extensions.get("network_stream") is response.extensions.get("network_stream")
debug_body: Final = JSON_OBJECT.validate_json(debug_response.content)
worker_pid: Final = debug_body.get("worker_pid")
assert isinstance(worker_pid, int), debug_body
body: Final = JSON_OBJECT.validate_json(response.content)
entries: Final = body.get("data")
assert isinstance(entries, list), body
count: Final = sum(object_value(entry).get("model_name") == group for entry in entries)
yield worker_pid, count
initial_counts: Final[Mapping[int, int]] = MappingProxyType({})
latest_counts: Final = accumulate(readbacks(), _record_latest_readback, initial=initial_counts)
for latest_by_worker in latest_counts:
if len(latest_by_worker) >= workers and all(count == deployments for count in latest_by_worker.values()):
return
raise AssertionError(f"Expected {deployments} deployments on {workers} workers before the readiness deadline")