forked from Karylab-cklius/vllm
Signed-off-by: hallerite <git@hallerite.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
71 lines
2.9 KiB
Python
71 lines
2.9 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
|
"""Unit tests for the disagg request/response protocol.
|
|
|
|
These tests intentionally avoid spinning up a server — they exercise the
|
|
pydantic validators on ``GenerateRequest`` directly so they run fast and
|
|
fail loudly if the validator semantics ever drift.
|
|
"""
|
|
|
|
import json
|
|
|
|
from vllm.entrypoints.serve.disagg.protocol import GenerateRequest
|
|
from vllm.sampling_params import SamplingParams
|
|
|
|
|
|
def _base_payload() -> dict:
|
|
return {"token_ids": [1, 2, 3], "sampling_params": {}}
|
|
|
|
|
|
def test_omitted_max_tokens_is_not_provided():
|
|
"""Body without ``max_tokens`` must surface as 'not provided' so the
|
|
server can apply its own default instead of the dataclass 16."""
|
|
req = GenerateRequest.model_validate(_base_payload())
|
|
# SamplingParams' dataclass default leaks through the parsed instance —
|
|
# this is exactly the bug the server-side defaulting works around.
|
|
assert req.sampling_params.max_tokens == 16
|
|
assert not req.is_sampling_param_provided("max_tokens")
|
|
|
|
|
|
def test_explicit_max_tokens_is_provided():
|
|
"""Even when the client picks the same value as the dataclass default,
|
|
it must register as explicitly set so the server won't override it."""
|
|
payload = _base_payload()
|
|
payload["sampling_params"] = {"max_tokens": 16}
|
|
req = GenerateRequest.model_validate(payload)
|
|
assert req.sampling_params.max_tokens == 16
|
|
assert req.is_sampling_param_provided("max_tokens")
|
|
|
|
payload["sampling_params"] = {"max_tokens": 256}
|
|
req = GenerateRequest.model_validate(payload)
|
|
assert req.sampling_params.max_tokens == 256
|
|
assert req.is_sampling_param_provided("max_tokens")
|
|
|
|
|
|
def test_other_fields_tracked_independently():
|
|
payload = _base_payload()
|
|
payload["sampling_params"] = {"temperature": 0.0}
|
|
req = GenerateRequest.model_validate(payload)
|
|
assert not req.is_sampling_param_provided("max_tokens")
|
|
assert req.is_sampling_param_provided("temperature")
|
|
|
|
|
|
def test_json_roundtrip_preserves_provided_keys():
|
|
payload = _base_payload()
|
|
payload["sampling_params"] = {"temperature": 0.5}
|
|
req = GenerateRequest.model_validate_json(json.dumps(payload))
|
|
assert not req.is_sampling_param_provided("max_tokens")
|
|
assert req.is_sampling_param_provided("temperature")
|
|
|
|
|
|
def test_internal_instance_construction_treats_all_as_provided():
|
|
"""When internal callers build ``GenerateRequest`` from a pre-resolved
|
|
``SamplingParams`` instance, every field is considered explicitly set
|
|
so server-side defaulting can't clobber values resolved upstream."""
|
|
sp = SamplingParams(max_tokens=500, temperature=0.0)
|
|
req = GenerateRequest(token_ids=[1, 2, 3], sampling_params=sp)
|
|
assert req.is_sampling_param_provided("max_tokens")
|
|
assert req.is_sampling_param_provided("temperature")
|
|
# And keys we never touched should also count as provided in this path.
|
|
assert req.is_sampling_param_provided("top_p")
|