mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-09 22:31:41 +00:00
* test(e2e): cover vendor strategy gaps for chat contract, image edits, auth, team activity Resolves the first slice of LIT-4778 (vendor API testing strategy): image edits happy path, chat multi-turn + validation + sanitization, LLM-route auth header matrix, and /team/daily/activity structure * test(e2e): expand vendor API strategy coverage across endpoints Adds validation cases on existing endpoint suites, plus vector stores, search, bedrock native, realtime HTTP secrets/calls, responses retrieve, files/batches contract, and chat stream SSE. Registers coverage cells for LIT-4778 * test(e2e): finish vendor strategy open items Audio transcription negatives, vector-store file attach/poll/search, OpenAI moderation category matrix across chat/messages/responses, and smoke model matrix for chat (LIT-4778) * test(e2e): harden vendor strategy suite against live env edges Fix stream [DONE] tracking, XSS no-crash contract, realtime model routing, vector store list/search models, responses validation, and provider-denied Bedrock paths so the suite is stable against a live proxy * test(e2e): rename suites, drop vendor_contract, fix greptile gaps Move shared status helpers into e2e_http, rename chat auth headers and chat security suites, remove vendor_contract and dev_config files_settings, and tighten transcription validation plus vector-store search assertions * test(e2e): route bedrock stream disconnects through e2e_http Catch mid-stream RequestException in the shared harness so bedrock native tests do not import requests directly
78 lines
3.4 KiB
Python
78 lines
3.4 KiB
Python
"""Live e2e: POST /v1/images/edits returns an edited image.
|
|
|
|
Registers an OpenAI image model, then sends a small PNG plus an edit prompt as a
|
|
multipart request to /v1/images/edits and asserts the response carries an image
|
|
(url or base64). /images/edits is a distinct native route from
|
|
/images/generations: it is multipart file upload with the image sent as the
|
|
`image` part, not a JSON body. The fixture image is a small generated 64x64 PNG,
|
|
so no external asset is needed.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import base64
|
|
|
|
import pytest
|
|
from e2e_config import unique_marker
|
|
from e2e_http import Result, UnknownApiError, unwrap
|
|
from endpoints_client import EndpointsClient, ImageEditForm, ImagesResult
|
|
from lifecycle import ResourceManager
|
|
from models import LiteLLMParamsBody
|
|
|
|
pytestmark = pytest.mark.e2e
|
|
|
|
_TEST_PNG = base64.b64decode(
|
|
"iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAS0lEQVR42u3PMQ0AAAwDoPo3"
|
|
"3UrYvQQckD4XAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB"
|
|
"AYHLAMpT0sIcNbcEAAAAAElFTkSuQmCC"
|
|
)
|
|
|
|
|
|
def _register_image_model(endpoints_client: EndpointsClient, resources: ResourceManager) -> tuple[str, str]:
|
|
model = f"e2e-image-edit-{unique_marker()}"
|
|
model_id = endpoints_client.create_model(
|
|
model,
|
|
LiteLLMParamsBody(model="openai/gpt-image-1", api_key="os.environ/OPENAI_API_KEY"),
|
|
)
|
|
resources.defer(lambda: endpoints_client.delete_model(model_id))
|
|
return model, resources.key()
|
|
|
|
|
|
def _assert_client_error(result: Result[ImagesResult], context: str) -> None:
|
|
match result:
|
|
case UnknownApiError(status_code=status) if 400 <= status < 500:
|
|
return
|
|
case other:
|
|
pytest.fail(f"{context}: expected 4xx, got {other!r}")
|
|
|
|
|
|
class TestImageEdit:
|
|
@pytest.mark.covers("llm.images_edits.openai.basic.nonstream.works")
|
|
def test_image_edit_returns_image(self, endpoints_client: EndpointsClient, resources: ResourceManager) -> None:
|
|
model, key = _register_image_model(endpoints_client, resources)
|
|
|
|
edited = unwrap(endpoints_client.image_edit(key, model, "Add a small red circle in the center", _TEST_PNG))
|
|
assert edited.data, f"/images/edits returned no data: {edited}"
|
|
first = edited.data[0]
|
|
assert first.b64_json or first.url, f"edited image has neither b64_json nor url: {first}"
|
|
|
|
@pytest.mark.covers("llm.images_edits.openai.input_validation.nonstream.works")
|
|
def test_empty_prompt_returns_error(self, endpoints_client: EndpointsClient, resources: ResourceManager) -> None:
|
|
model, key = _register_image_model(endpoints_client, resources)
|
|
result = endpoints_client.image_edit(key, model, "", _TEST_PNG)
|
|
_assert_client_error(result, "empty image-edit prompt")
|
|
|
|
@pytest.mark.covers("llm.images_edits.openai.input_validation.nonstream.works")
|
|
def test_empty_image_returns_error(self, endpoints_client: EndpointsClient, resources: ResourceManager) -> None:
|
|
model, key = _register_image_model(endpoints_client, resources)
|
|
result = endpoints_client.proxy.transport.upload(
|
|
"/v1/images/edits",
|
|
headers=endpoints_client.proxy.transport.bearer(key),
|
|
form=ImageEditForm(model=model, prompt="add a red circle"),
|
|
filename="image.png",
|
|
content=b"",
|
|
file_content_type="image/png",
|
|
file_field="image",
|
|
response_type=ImagesResult,
|
|
)
|
|
_assert_client_error(result, "empty image-edit file")
|