From ff418ffb9c15021fe173d9f0b73040aff17c60cc Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Thu, 27 Aug 2026 14:29:53 -0700 Subject: [PATCH] test(e2e): serve the vision image from our own fixture The two vision tests pointed at a Wikipedia-hosted cat photo, so every run depended on upload.wikimedia.org staying up and unthrottled. It throttled, and the 429 surfaced as a bedrock APIConnectionError, which reads as a gateway failure rather than what it was. The image is now a fixture in the repo, passed as a data URL. That also puts the two providers on the same bytes: litellm downloads the image itself for bedrock, while openai is handed the link and fetches it from its own servers, so the hosted URL quietly meant the two tests were not testing the same thing. The image was generated for this repo rather than borrowed, so nothing here carries a third-party license. Also drops a stale comment about openai prompt caching that sat above the vision helper; no caching test uses it. --- tests/e2e/llm_translation/fixtures/cat.jpg | Bin 0 -> 31243 bytes .../test_chat_completions_regression_e2e.py | 22 ++++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 tests/e2e/llm_translation/fixtures/cat.jpg diff --git a/tests/e2e/llm_translation/fixtures/cat.jpg b/tests/e2e/llm_translation/fixtures/cat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..103c370b2e2fae87b2cdde49eef8962077a8e314 GIT binary patch literal 31243 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 tuple[str, str]: return name, arguments -CAT_IMAGE_URL = "https://upload.wikimedia.org/wikipedia/commons/3/3a/Cat03.jpg" +_FIXTURES_DIR: Final = Path(__file__).parent / "fixtures" +CAT_IMAGE: Final = _FIXTURES_DIR / "cat.jpg" OPENAI_VISION_BACKEND = "openai/gpt-4o" -# OpenAI caches a shared prompt prefix once it exceeds ~1024 tokens; this is well -# past that, so a repeat call reports cached prompt tokens. + +def _cat_image_data_url() -> str: + """The vision image as a data URL, read from a fixture we own. + + An https URL would make every vision run depend on a third-party host staying + up and unthrottled, and a 429 from that host reads as a gateway failure. It also + changes what is under test per provider: litellm downloads the image itself for + bedrock, while openai is handed the link and fetches it from its own servers. A + data URL removes the host and puts both providers on the same bytes.""" + return "data:image/jpeg;base64," + base64.b64encode(CAT_IMAGE.read_bytes()).decode() + + def _vision_messages() -> list[ChatMessage]: return [ ChatMessage( role="user", content=[ TextContentPart(text="What animal is in this image? Answer in one word."), - ImageContentPart(image_url=ImageUrl(url=CAT_IMAGE_URL)), + ImageContentPart(image_url=ImageUrl(url=_cat_image_data_url())), ], ) ]