diff --git a/.buildkite/test_areas/misc.yaml b/.buildkite/test_areas/misc.yaml index f4b07ffd97..0c0e8c9a4d 100644 --- a/.buildkite/test_areas/misc.yaml +++ b/.buildkite/test_areas/misc.yaml @@ -496,15 +496,22 @@ steps: - vllm/assets/ - vllm/config/ - vllm/device_allocator/ + - vllm/connections.py - vllm/engine/arg_utils.py - vllm/entrypoints/chat_utils.py - vllm/entrypoints/mcp/ - vllm/entrypoints/openai/chat_completion/protocol.py + - vllm/entrypoints/openai/completion/protocol.py + - vllm/entrypoints/openai/responses/protocol.py - vllm/entrypoints/generate/base/protocol.py + - vllm/env_override.py - vllm/envs.py - vllm/exceptions.py - vllm/inputs/ + - vllm/logging_utils/ + - vllm/logprobs.py - vllm/model_executor/layers/quantization/quark/ + - vllm/model_executor/model_loader/tensorizer.py - vllm/multimodal/ - vllm/outputs.py - vllm/parser/ @@ -514,17 +521,38 @@ steps: - vllm/reasoning/ - vllm/renderers/ - vllm/sampling_params.py + - vllm/scalar_type.py - vllm/tokenizers/ - vllm/tool_parsers/ - vllm/transformers_utils/ + - vllm/triton_utils/ - vllm/utils/ - vllm/v1/ + - vllm/version.py + - cmake/utils.cmake + - tests/test_access_log_filter.py + - tests/test_attention_backend_registry.py + - tests/test_audio_media_size_precheck.py + - tests/test_cmake_utils.py + - tests/test_connections.py + - tests/test_embedded_commit.py - tests/test_envs.py + - tests/test_force_first_config.py + - tests/test_fxgraphcache_pickle_patch.py + - tests/test_logprobs.py - tests/test_outputs.py - tests/test_pcp_dp.py - tests/test_pooling_params.py + - tests/test_quantization_revision_pin.py - tests/test_ray_env.py + - tests/test_ray_env_utils.py + - tests/test_request_input_bounds.py - tests/test_sampling_params.py + - tests/test_scalartype.py + - tests/test_tensorizer_revision_pin.py + - tests/test_triton_utils.py + - tests/test_version.py + - tests/test_zen_cpu_platform_detection.py - tests/multimodal - tests/renderers - tests/standalone_tests/lazy_imports.py @@ -540,14 +568,32 @@ steps: - tests/device_allocator device: cpu-small commands: + - pip install cmake # test_cmake_utils.py shells out to cmake; the CPU image has none - python3 standalone_tests/lazy_imports.py - pytest -v -s device_allocator + - pytest -v -s test_access_log_filter.py + - pytest -v -s test_attention_backend_registry.py + - pytest -v -s test_audio_media_size_precheck.py + - pytest -v -s test_cmake_utils.py + - pytest -v -s test_connections.py + - pytest -v -s test_embedded_commit.py - pytest -v -s test_envs.py + - pytest -v -s test_force_first_config.py + - pytest -v -s test_fxgraphcache_pickle_patch.py + - pytest -v -s test_logprobs.py - pytest -v -s test_outputs.py - pytest -v -s test_pcp_dp.py - pytest -v -s test_pooling_params.py + - pytest -v -s test_quantization_revision_pin.py - pytest -v -s test_ray_env.py + - pytest -v -s test_ray_env_utils.py + - pytest -v -s test_request_input_bounds.py - pytest -v -s test_sampling_params.py + - pytest -v -s test_scalartype.py + - pytest -v -s test_tensorizer_revision_pin.py + - pytest -v -s test_triton_utils.py + - pytest -v -s test_version.py + - pytest -v -s test_zen_cpu_platform_detection.py - pytest -v -s tokenizers_ - pytest -v -s parser - pytest -v -s transformers_utils diff --git a/docker/Dockerfile.cpu b/docker/Dockerfile.cpu index 43172fbdcf..ad36c18d49 100644 --- a/docker/Dockerfile.cpu +++ b/docker/Dockerfile.cpu @@ -433,6 +433,8 @@ ADD ./benchmarks/ ./benchmarks/ ADD ./vllm/collect_env.py . ADD ./docker/ ./docker/ ADD ./.buildkite/ ./.buildkite/ +# cmake/ is needed by tests/test_cmake_utils.py, which includes cmake/utils.cmake. +ADD ./cmake/ ./cmake/ # tools/ carries repo-tooling code that a few tests exercise directly # (e.g. tests/tools/test_check_test_tethering.py imports # tools.pre_commit.check_test_tethering). diff --git a/tests/test_request_input_bounds.py b/tests/test_request_input_bounds.py index 7f79d4ba47..514a450f73 100644 --- a/tests/test_request_input_bounds.py +++ b/tests/test_request_input_bounds.py @@ -43,6 +43,7 @@ def prompt_embeds_processor(): logits_processors=None, is_diffusion=False, return_sampling_mask=False, + supports_multimodal_inputs=False, ) model_config.get_vocab_size.return_value = 32 model_config.try_get_generation_config.return_value = {} @@ -53,9 +54,7 @@ def prompt_embeds_processor(): ) renderer = Mock(tokenizer=None) renderer.get_eos_token_id.return_value = None - registry = Mock() - registry.supports_multimodal_inputs.return_value = False - return InputProcessor(config, renderer, mm_registry=registry) + return InputProcessor(config, renderer, mm_registry=Mock()) @pytest.mark.parametrize("mask_len", [0, 1, 2, 4]) diff --git a/tests/test_triton_utils.py b/tests/test_triton_utils.py index 7f6422466f..3d7c8aeed2 100644 --- a/tests/test_triton_utils.py +++ b/tests/test_triton_utils.py @@ -10,10 +10,13 @@ from vllm.triton_utils import importing as triton_importing from vllm.triton_utils.importing import TritonLanguagePlaceholder, TritonPlaceholder -def _has_triton_for_backends(**drivers: bool) -> bool: +def _has_triton_for_backends(*, vllm_version: str = "0.0.0", **drivers: bool) -> bool: """Re-evaluate ``HAS_TRITON`` against a synthetic ``triton.backends`` map. ``drivers`` maps backend name to whether its driver reports itself active. + ``vllm_version`` selects the build type: importing.py takes its Triton-CPU + branch only when "cpu" is in the installed vLLM version, so pin it rather + than depending on the real install (the CPU CI image is a "+cpu" build). """ backends = {} for name, is_active in drivers.items(): @@ -34,6 +37,7 @@ def _has_triton_for_backends(**drivers: bool) -> bool: with ( mock.patch.dict(sys.modules, patched_modules), mock.patch.dict("os.environ", {}, clear=True), + mock.patch("importlib.metadata.version", return_value=vllm_version), ): return importlib.reload(triton_importing).HAS_TRITON finally: @@ -129,19 +133,50 @@ def test_cpu_backend_alone_disables_triton(): assert _has_triton_for_backends(cpu=True) is False +def test_cpu_build_with_cpu_backend_keeps_triton(): + assert _has_triton_for_backends(vllm_version="0.0.0+cpu", cpu=True) is True + + +def test_cpu_build_without_cpu_backend_disables_triton(): + assert _has_triton_for_backends(vllm_version="0.0.0+cpu", amd=True) is False + + def test_no_triton_fallback(): - # clear existing triton modules - sys.modules.pop("triton", None) - sys.modules.pop("triton.language", None) - sys.modules.pop("vllm.triton_utils", None) - sys.modules.pop("vllm.triton_utils.importing", None) + # Save the real modules so they can be put back afterward - popping them + # (rather than mock.patch.dict alone) is what forces vllm.triton_utils to + # be freshly, unmemoized re-imported under the "triton is absent" + # condition below. + saved_modules = { + name: sys.modules.get(name) + for name in ( + "triton", + "triton.language", + "vllm.triton_utils", + "vllm.triton_utils.importing", + ) + } + for name in saved_modules: + sys.modules.pop(name, None) - # mock triton not being installed - with mock.patch.dict(sys.modules, {"triton": None}): - from vllm.triton_utils import HAS_TRITON, tl, triton + try: + # mock triton not being installed + with mock.patch.dict(sys.modules, {"triton": None}): + from vllm.triton_utils import HAS_TRITON, tl, triton - assert HAS_TRITON is False - assert triton.__class__.__name__ == "TritonPlaceholder" - assert triton.language.__class__.__name__ == "TritonLanguagePlaceholder" - assert tl.__class__.__name__ == "TritonLanguagePlaceholder" - assert tl.constexpr(2**31 - 1) == 2**31 - 1 + assert HAS_TRITON is False + assert triton.__class__.__name__ == "TritonPlaceholder" + assert triton.language.__class__.__name__ == "TritonLanguagePlaceholder" + assert tl.__class__.__name__ == "TritonLanguagePlaceholder" + assert tl.constexpr(2**31 - 1) == 2**31 - 1 + finally: + # The pops above are outside mock.patch.dict's scope, so exiting the + # `with` restores "triton" to absent, not to the real module - unlike + # _has_triton_for_backends above, nothing here puts it back. Left + # alone, every subsequent import of vllm.triton_utils in this process + # (including other test files, and other tests' cleanup fixtures that + # need real triton) would get this fake, HAS_TRITON=False module. + for name, module in saved_modules.items(): + if module is not None: + sys.modules[name] = module + else: + sys.modules.pop(name, None) diff --git a/tests/test_version.py b/tests/test_version.py index 928f742f1d..67cb999e13 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -13,7 +13,10 @@ def test_version_is_defined(): def test_version_tuple(): - assert len(version.__version_tuple__) in (3, 4, 5) + # (major, minor, patch) plus optional pre-release tag, dev-distance, and + # git-hash components - setuptools_scm can emit any combination of them, + # e.g. 6 when a dev build sits on top of an rc-tagged commit. + assert len(version.__version_tuple__) >= 3 @pytest.mark.parametrize( diff --git a/tests/test_zen_cpu_platform_detection.py b/tests/test_zen_cpu_platform_detection.py index 0c99c6568a..505d2d3bfd 100644 --- a/tests/test_zen_cpu_platform_detection.py +++ b/tests/test_zen_cpu_platform_detection.py @@ -13,6 +13,23 @@ from vllm.platforms import ( ) +@pytest.fixture +def caplog_vllm(caplog): + """`caplog`, but also captures vLLM's loggers. + + vllm/logger.py configures the "vllm" logger with propagate=False, so + records from child loggers like "vllm.platforms" reach vLLM's own + handler but never bubble up to the root logger where plain `caplog` + listens. Attach caplog's handler directly to "vllm" to see them too. + """ + logger = logging.getLogger("vllm") + logger.addHandler(caplog.handler) + try: + yield caplog + finally: + logger.removeHandler(caplog.handler) + + def test_is_amd_zen_cpu_detects_amd_with_avx512(): cpuinfo = "vendor_id: AuthenticAMD\nflags: avx avx2 avx512f avx512bw" with ( @@ -65,7 +82,7 @@ def test_cpu_target_selects_cpu_platform_from_non_cpu_wheel( rocm_plugin.assert_not_called() -def test_broken_zentorch_falls_back_to_cpu_platform(caplog): +def test_broken_zentorch_falls_back_to_cpu_platform(caplog_vllm): original_import = builtins.__import__ def import_with_broken_zentorch(name, *args, **kwargs): @@ -84,16 +101,16 @@ def test_broken_zentorch_falls_back_to_cpu_platform(caplog): patch("vllm.platforms.vllm_version_matches_substr", return_value=True), patch("vllm.platforms._is_amd_zen_cpu", return_value=True), patch.object(builtins, "__import__", side_effect=import_with_broken_zentorch), - caplog.at_level(logging.DEBUG, logger="vllm.platforms"), + caplog_vllm.at_level(logging.DEBUG, logger="vllm.platforms"), ): platform = resolve_current_platform_cls_qualname() assert platform == "vllm.platforms.cpu.CpuPlatform" - assert "zentorch failed to import" in caplog.text - assert "OSError: incompatible shared library" in caplog.text + assert "zentorch failed to import" in caplog_vllm.text + assert "OSError: incompatible shared library" in caplog_vllm.text -def test_zentorch_failure_other_than_oserror_is_not_recovered(caplog): +def test_zentorch_failure_other_than_oserror_is_not_recovered(caplog_vllm): original_import = builtins.__import__ def import_with_broken_zentorch(name, *args, **kwargs): @@ -112,15 +129,15 @@ def test_zentorch_failure_other_than_oserror_is_not_recovered(caplog): patch("vllm.platforms.vllm_version_matches_substr", return_value=True), patch("vllm.platforms._is_amd_zen_cpu", return_value=True), patch.object(builtins, "__import__", side_effect=import_with_broken_zentorch), - caplog.at_level(logging.DEBUG, logger="vllm.platforms"), + caplog_vllm.at_level(logging.DEBUG, logger="vllm.platforms"), ): platform = resolve_current_platform_cls_qualname() assert platform == "vllm.platforms.interface.UnspecifiedPlatform" - assert "RuntimeError: unknown zentorch failure" in caplog.text + assert "RuntimeError: unknown zentorch failure" in caplog_vllm.text -def test_platform_plugin_failure_is_logged(caplog): +def test_platform_plugin_failure_is_logged(caplog_vllm): def failing_plugin(): raise RuntimeError("plugin exploded") @@ -132,10 +149,10 @@ def test_platform_plugin_failure_is_logged(caplog): clear=True, ), patch("vllm.platforms.load_plugins_by_group", return_value={}), - caplog.at_level(logging.DEBUG, logger="vllm.platforms"), + caplog_vllm.at_level(logging.DEBUG, logger="vllm.platforms"), ): platform = resolve_current_platform_cls_qualname() assert platform == "vllm.platforms.interface.UnspecifiedPlatform" - assert "Platform plugin cpu failed during detection" in caplog.text - assert "RuntimeError: plugin exploded" in caplog.text + assert "Platform plugin cpu failed during detection" in caplog_vllm.text + assert "RuntimeError: plugin exploded" in caplog_vllm.text diff --git a/tools/pre_commit/test_tethering_allowlist.txt b/tools/pre_commit/test_tethering_allowlist.txt index 80b4aaec4c..cc5294cf26 100644 --- a/tools/pre_commit/test_tethering_allowlist.txt +++ b/tools/pre_commit/test_tethering_allowlist.txt @@ -59,27 +59,6 @@ tests/models/test_dspark_mla.py # no models_*.yaml job collects this path tests/models/test_language_model_cache_is_weak.py # no models_*.yaml job collects this path tests/models/transformers/test_layer_registry.py # no models_*.yaml job collects this path -# tests/ root-level - misc.yaml runs a hand-picked set of these by name -# (test_regression.py, test_envs.py, test_outputs.py, test_pooling_params.py); -# the rest are unreferenced. -tests/test_access_log_filter.py # root test_*.py not in misc.yaml's by-name list -tests/test_attention_backend_registry.py # root test_*.py not in misc.yaml's by-name list -tests/test_audio_media_size_precheck.py # root test_*.py not in misc.yaml's by-name list -tests/test_cmake_utils.py # root test_*.py not in misc.yaml's by-name list -tests/test_connections.py # root test_*.py not in misc.yaml's by-name list -tests/test_embedded_commit.py # root test_*.py not in misc.yaml's by-name list -tests/test_force_first_config.py # root test_*.py not in misc.yaml's by-name list -tests/test_fxgraphcache_pickle_patch.py # root test_*.py not in misc.yaml's by-name list -tests/test_logprobs.py # root test_*.py not in misc.yaml's by-name list -tests/test_quantization_revision_pin.py # root test_*.py not in misc.yaml's by-name list -tests/test_ray_env_utils.py # root test_*.py not in misc.yaml's by-name list -tests/test_request_input_bounds.py # root test_*.py not in misc.yaml's by-name list -tests/test_scalartype.py # root test_*.py not in misc.yaml's by-name list -tests/test_tensorizer_revision_pin.py # root test_*.py not in misc.yaml's by-name list -tests/test_triton_utils.py # root test_*.py not in misc.yaml's by-name list -tests/test_version.py # root test_*.py not in misc.yaml's by-name list -tests/test_zen_cpu_platform_detection.py # root test_*.py not in misc.yaml's by-name list - # tests/v1/ - the v1 subtree is otherwise covered by many `pytest v1/...` jobs. tests/v1/e2e/test_replayssm_decode.py # ReplaySSM decode test (#52506) wired into no job tests/v1/ec_connector/integration/test_epd_correctness.py # run_epd_correctness_test.sh exists but no Buildkite job invokes it @@ -91,10 +70,3 @@ tests/platforms/test_cpu.py # CPU-only unit test; no job targets tests/platform # tests/tools/ tests/tools/test_config_validator.py # logic covered by the validate-config pre-commit hook; no test_areas job - -# tests/watermarking/ - added by #54053 (2026-09-09), no Buildkite job collects the dir yet -tests/watermarking/test_detection.py # watermarking feature (#54053); no job collects tests/watermarking/ -tests/watermarking/test_gumbel.py # watermarking feature (#54053); no job collects tests/watermarking/ -tests/watermarking/test_prf.py # watermarking feature (#54053); no job collects tests/watermarking/ -tests/watermarking/test_watermarking.py # watermarking feature (#54053); no job collects tests/watermarking/ -tests/watermarking/test_watermarking_e2e.py # watermarking hardening (#56309); no job collects tests/watermarking/ diff --git a/vllm/version.py b/vllm/version.py index 63095f8bce..76884f4908 100644 --- a/vllm/version.py +++ b/vllm/version.py @@ -26,8 +26,6 @@ def _prev_minor_version_was(version_str): if __version_tuple__[0:2] == (0, 0): return True - # Note - this won't do the right thing when we release 1.0! - assert __version_tuple__[0] == 0 assert isinstance(__version_tuple__[1], int) return version_str == f"{__version_tuple__[0]}.{__version_tuple__[1] - 1}"