From 85d1f92ee58de7cf65bcfd9a02fc0a4c3e3dc9d3 Mon Sep 17 00:00:00 2001 From: tzhouam Date: Thu, 3 Sep 2026 14:58:27 +0800 Subject: [PATCH] test: guard prompt-update helpers against upstream removal The MiniCPM-o select_text breakage cost eight CI jobs and surfaced only as "Engine core initialization failed", because the replacement closures that call these helpers are not driven by any unit test. A static check is what actually catches the next removal. Resolves each PromptUpdateDetails attribute referenced under vllm_omni/ against the installed class, so it tracks upstream instead of a hard-coded list, and names the offending file in the failure. Verified by reintroducing select_text: the guard fails with that file named, and passes once reverted. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_0146Xu5Sgj4vXxLxvLjV5YPj Signed-off-by: tzhouam --- .../test_upstream_prompt_update_api.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 tests/model_executor/test_upstream_prompt_update_api.py diff --git a/tests/model_executor/test_upstream_prompt_update_api.py b/tests/model_executor/test_upstream_prompt_update_api.py new file mode 100644 index 000000000..da31980c2 --- /dev/null +++ b/tests/model_executor/test_upstream_prompt_update_api.py @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project +"""Guard that Omni only calls prompt-update helpers upstream still provides. + +vLLM 0.29 removed ``PromptUpdateDetails.select_text`` in favour of the +token-oriented ``select_token_id`` / ``select_token_ids``. Three MiniCPM-o call +sites survived the rebase and only failed at engine-core startup, where the +traceback surfaced as an opaque "Engine core initialization failed" across eight +CI jobs. + +These helpers are referenced from replacement closures that no unit test drives, +so a static check is what actually catches the next removal. It resolves the +attribute against the installed class rather than a hard-coded list, so it +follows upstream automatically. +""" + +from __future__ import annotations + +import ast +from pathlib import Path + +import pytest +from vllm.multimodal.processing.processor import PromptUpdateDetails + +pytestmark = [pytest.mark.core_model, pytest.mark.cpu] + +_OMNI_ROOT = Path(__file__).resolve().parents[2] / "vllm_omni" +_GUARDED = "PromptUpdateDetails" + + +def _referenced_attributes() -> dict[str, set[str]]: + """Map ``PromptUpdateDetails.`` -> source files referencing it.""" + found: dict[str, set[str]] = {} + for path in _OMNI_ROOT.rglob("*.py"): + try: + tree = ast.parse(path.read_text(encoding="utf-8")) + except (SyntaxError, UnicodeDecodeError): # pragma: no cover - defensive + continue + for node in ast.walk(tree): + if isinstance(node, ast.Attribute) and isinstance(node.value, ast.Name) and node.value.id == _GUARDED: + found.setdefault(node.attr, set()).add(str(path.relative_to(_OMNI_ROOT.parent))) + return found + + +def test_omni_only_uses_prompt_update_helpers_that_exist_upstream() -> None: + referenced = _referenced_attributes() + assert referenced, "expected Omni to reference PromptUpdateDetails somewhere" + + missing = {attr: sorted(files) for attr, files in referenced.items() if not hasattr(PromptUpdateDetails, attr)} + + assert not missing, ( + "Omni calls PromptUpdateDetails helpers that the installed vLLM does not " + f"provide: {missing}. Upstream moved prompt updates to token ids; use " + "select_token_id/select_token_ids with the encoded text." + ) + + +def test_token_oriented_helpers_are_the_ones_upstream_exposes() -> None: + """Pin the replacements, so their removal fails here and not at startup.""" + assert hasattr(PromptUpdateDetails, "select_token_id") + assert hasattr(PromptUpdateDetails, "select_token_ids") + assert not hasattr(PromptUpdateDetails, "select_text"), ( + "select_text is back upstream; re-check the MiniCPM-o replacements." + )