| 1 | # SPDX-License-Identifier: Apache-2.0 |
| 2 | # SPDX-FileCopyrightText: Copyright contributors to the vLLM project |
| 3 | import pytest |
| 4 | |
| 5 | from vllm.engine.arg_utils import EngineArgs |
| 6 | from vllm.model_executor.layers.quantization.quark.utils import deep_compare |
| 7 | |
| 8 | |
| 9 | def test_cuda_empty_vs_unset_configs(monkeypatch: pytest.MonkeyPatch): |
| 10 | """Test that configs created with normal (untouched) CUDA_VISIBLE_DEVICES |
| 11 | and CUDA_VISIBLE_DEVICES="" are equivalent. This ensures consistent |
| 12 | behavior regardless of whether GPU visibility is disabled via empty string |
| 13 | or left in its normal state. |
| 14 | """ |
| 15 | |
| 16 | def create_config(): |
| 17 | engine_args = EngineArgs( |
| 18 | model="deepseek-ai/DeepSeek-V2-Lite", trust_remote_code=True |
| 19 | ) |
| 20 | return engine_args.create_engine_config() |
| 21 | |
| 22 | # Create config with CUDA_VISIBLE_DEVICES set normally |
| 23 | normal_config = create_config() |
| 24 | |
| 25 | # Create config with CUDA_VISIBLE_DEVICES="" |
| 26 | with monkeypatch.context() as m: |
| 27 | m.setenv("CUDA_VISIBLE_DEVICES", "") |
| 28 | empty_config = create_config() |
| 29 | |
| 30 | normal_config_dict = vars(normal_config) |
| 31 | empty_config_dict = vars(empty_config) |
| 32 | |
| 33 | # Remove instance_id before comparison as it's expected to be different |
| 34 | normal_config_dict.pop("instance_id", None) |
| 35 | empty_config_dict.pop("instance_id", None) |
| 36 | |
| 37 | assert deep_compare(normal_config_dict, empty_config_dict), ( |
| 38 | 'Configs with normal CUDA_VISIBLE_DEVICES and CUDA_VISIBLE_DEVICES=""' |
| 39 | " should be equivalent" |
| 40 | ) |
| 41 | |
| 42 | |
| 43 | def test_ray_runtime_env(monkeypatch: pytest.MonkeyPatch): |
| 44 | # In testing, this method needs to be nested inside as ray does not |
| 45 | # see the test module. |
| 46 | def create_config(): |
| 47 | engine_args = EngineArgs( |
| 48 | model="deepseek-ai/DeepSeek-V2-Lite", trust_remote_code=True |
| 49 | ) |
| 50 | return engine_args.create_engine_config() |
| 51 | |
| 52 | config = create_config() |
| 53 | parallel_config = config.parallel_config |
| 54 | assert parallel_config.ray_runtime_env is None |
| 55 | |
| 56 | import ray |
| 57 | |
| 58 | ray.init() |
| 59 | |
| 60 | runtime_env = { |
| 61 | "env_vars": { |
| 62 | "TEST_ENV_VAR": "test_value", |
| 63 | # In future ray versions, this will be default, so when setting a |
| 64 | # task or actor with num_gpus=None/0, the visible devices env var |
| 65 | # won't be overridden resulting in no GPUs being visible on a gpu |
| 66 | # machine. |
| 67 | "RAY_ACCEL_ENV_VAR_OVERRIDE_ON_ZERO": "0", |
| 68 | }, |
| 69 | } |
| 70 | |
| 71 | config_ref = ray.remote(create_config).options(runtime_env=runtime_env).remote() |
| 72 | |
| 73 | config = ray.get(config_ref) |
| 74 | parallel_config = config.parallel_config |
| 75 | assert parallel_config.ray_runtime_env is not None |
| 76 | assert ( |
| 77 | parallel_config.ray_runtime_env.env_vars().get("TEST_ENV_VAR") == "test_value" |
| 78 | ) |
| 79 | |
| 80 | ray.shutdown() |
| 81 | |
| 82 | |
| 83 | def test_unrecognized_env(monkeypatch): |
| 84 | import os |
| 85 | |
| 86 | from vllm.envs import environment_variables |
| 87 | |
| 88 | # Remove any existing unrecognized VLLM env vars that might interfere |
| 89 | for env in list(os.environ): |
| 90 | if env.startswith("VLLM_") and env not in environment_variables: |
| 91 | monkeypatch.delenv(env, raising=False) |
| 92 | |
| 93 | # Test that if fail_on_environ_validation is True, then an error |
| 94 | # is raised when an unrecognized vLLM environment variable is set |
| 95 | monkeypatch.setenv("VLLM_UNRECOGNIZED_ENV_VAR", "some_value") |
| 96 | engine_args = EngineArgs( |
| 97 | fail_on_environ_validation=True, |
| 98 | ) |
| 99 | with pytest.raises(ValueError, match="Unknown vLLM environment variable detected"): |
| 100 | engine_args.create_engine_config() |
| 101 | |
| 102 | # Test that if fail_on_environ_validation is False, then no error is raised |
| 103 | engine_args = EngineArgs() |
| 104 | engine_args.create_engine_config() |
| 105 | |
| 106 | # Test that when the unrecognized env var is removed, no error is raised |
| 107 | monkeypatch.delenv("VLLM_UNRECOGNIZED_ENV_VAR") |
| 108 | engine_args = EngineArgs( |
| 109 | fail_on_environ_validation=True, |
| 110 | ) |
| 111 | engine_args.create_engine_config() |
| 112 | |
| 113 | |
| 114 | def test_get_diff_sampling_param_includes_penalties(): |
| 115 | """``--override-generation-config`` must apply presence_penalty and |
| 116 | frequency_penalty as server-side defaults, like the other sampling |
| 117 | params. Regression test for the whitelist silently dropping them. |
| 118 | |
| 119 | Called unbound with a lightweight stand-in so no model is loaded: |
| 120 | generation_config="vllm" makes the method skip try_get_generation_config |
| 121 | and read only override_generation_config. |
| 122 | """ |
| 123 | from types import SimpleNamespace |
| 124 | |
| 125 | from vllm.config.model import ModelConfig |
| 126 | |
| 127 | fake = SimpleNamespace( |
| 128 | generation_config="vllm", |
| 129 | override_generation_config={ |
| 130 | "presence_penalty": 1.5, |
| 131 | "frequency_penalty": 0.5, |
| 132 | "temperature": 0.6, |
| 133 | }, |
| 134 | ) |
| 135 | |
| 136 | diff = ModelConfig.get_diff_sampling_param(fake) |
| 137 | |
| 138 | assert diff["presence_penalty"] == 1.5 |
| 139 | assert diff["frequency_penalty"] == 0.5 |
| 140 | assert diff["temperature"] == 0.6 |
| 141 | |
| 142 | |
| 143 | def test_generation_config_penalties_survive_diff_sampling_filter(): |
| 144 | """``generation_config.json`` penalties must survive the diff-sampling |
| 145 | whitelist (regression for #50767, auto path). |
| 146 | |
| 147 | Covers the ``generation_config="auto"`` branch, where the override |
| 148 | dict is empty and the values come from ``try_get_generation_config``. |
| 149 | """ |
| 150 | from types import SimpleNamespace |
| 151 | |
| 152 | from vllm.config.model import ModelConfig |
| 153 | |
| 154 | fake = SimpleNamespace( |
| 155 | generation_config="auto", |
| 156 | override_generation_config={}, |
| 157 | try_get_generation_config=lambda: { |
| 158 | "presence_penalty": 1.1, |
| 159 | "frequency_penalty": 0.7, |
| 160 | "temperature": 0.9, |
| 161 | }, |
| 162 | ) |
| 163 | |
| 164 | diff = ModelConfig.get_diff_sampling_param(fake) |
| 165 | |
| 166 | assert diff["presence_penalty"] == 1.1 |
| 167 | assert diff["frequency_penalty"] == 0.7 |
| 168 | assert diff["temperature"] == 0.9 |