litellm/tests/integration/management/test_model_deployment_lifecycle.py
devin-ai-integration[bot] 1dbde0845e
test: migrate SDK and proxy-booting legacy CircleCI tests to their tiers (#45758)
* test: move guardrails, image, audio, batches, search legacy tests to unit

* test: restore the custom guardrail and remaining chunk 1 unit rows

* test: move the ocr matrix to e2e

* test: drop comments from moved tests and fix vertex ocr credentials

* test: move litellm utils and unified google legacy tests to their tiers

* test: move logging callback and pass-through unit legacy tests to their tiers

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

* test: move store_model_in_db legacy tests and start the admin ui migration

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

* test: finish the proxy job rows and drop their CircleCI jobs

Moves the remaining multi-instance, openai endpoint, otel, pass-through and
top-level proxy tests into tests/integration with scripted upstreams, rewrites
the weak replacements to assert the outbound wire and exact responses, and
removes the build_and_test job group this PR owns from CircleCI

* test: tighten the key generation and error log assertions, rename migrated unit files to their mapped names

* test: shard the pagerduty unit tests and record the rust harness file on the coverage allowlist

* test: drive the SSO sign-in tests through a scripted IdP and isolate the cost center stand-in

* test: type the e2e beta header, prompt cache and secret manager values

* test: assert the missing model error message on the OpenAI routes

* test: drop the deleted otel base class import and restore mcp redaction and exact langfuse usage checks

* test: make the langfuse fixture directory a package for the layout check

* test: restore collected no-match cases, real langfuse and gcs payload checks, and gate the aws secret lane

* test: keep the ocr e2e pdf fixture next to the test

* test: put meta below covers on the streaming tool search e2e

* test: run the OCR matrix against a scripted upstream and fix two runner-only e2e failures

* test: count only OCR calls in the OCR matrix recorder

* test: pin OCR parse bodies and billed cost, group new e2e cases into classes

* ci: restore the python image anchor dropped in the main sync

---------

Co-authored-by: yuneng <yuneng@berri.ai>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-11 00:17:21 -07:00

77 lines
3.3 KiB
Python

import json
import uuid
from typing import Final
from tests.integration._support.client import Gateway, object_value, string_value
from tests.integration._support.wire import Reply, Request, wire_server
def _delete_model_if_present(gateway: Gateway, identity: str) -> None:
if gateway.request("GET", "/model/info", params={"litellm_model_id": identity}).status_code == 200:
gateway.post("/model/delete", {"id": identity})
def test_model_deployment_can_be_used_and_deleted(gateway: Gateway) -> None:
model: Final = f"lifecycle-model-{uuid.uuid4().hex}"
identity: Final = f"lifecycle-model-id-{uuid.uuid4().hex}"
def upstream(request: Request) -> Reply:
body: Final = json.loads(request.body)
assert body["messages"] == [{"role": "user", "content": "model lifecycle"}]
return Reply(
body=json.dumps(
{
"id": "model-lifecycle-response",
"object": "chat.completion",
"created": 1,
"model": "gpt-4o-mini",
"choices": [
{
"index": 0,
"message": {"role": "assistant", "content": "available"},
"finish_reason": "stop",
}
],
"usage": {"prompt_tokens": 2, "completion_tokens": 1, "total_tokens": 3},
}
).encode(),
)
with gateway.scenario() as scenario:
with wire_server(upstream) as provider:
created: Final = gateway.post(
"/model/new",
{
"model_name": model,
"litellm_params": {
"model": "openai/gpt-4o-mini",
"api_base": f"{provider.url}/v1",
"api_key": "synthetic-model-key",
},
"model_info": {"id": identity},
},
)
assert string_value(object_value(created["model_info"])["id"]) == identity
scenario.cleanups.callback(_delete_model_if_present, gateway, identity)
response: Final = gateway.request(
"POST",
"/v1/chat/completions",
{"model": model, "messages": [{"role": "user", "content": "model lifecycle"}]},
)
assert response.status_code == 200, response.text
assert response.json()["choices"][0]["message"]["content"] == "available"
deleted: Final = gateway.request("POST", "/model/delete", {"id": identity})
assert deleted.status_code == 200, deleted.text
remaining: Final = gateway.request("GET", "/model/info", params={"litellm_model_id": identity})
assert remaining.status_code == 400, remaining.text
assert f"Model id = {identity} not found" in remaining.text
unavailable: Final = gateway.request(
"POST",
"/v1/chat/completions",
{"model": model, "messages": [{"role": "user", "content": "model lifecycle"}]},
)
assert unavailable.status_code == 400, unavailable.text
assert f"Invalid model name passed in model={model}" in unavailable.text