Skip to content

Commit 07d0eed

Browse files
tarukumarnjhill
authored andcommitted
Add property-based testing for vLLM endpoints using an API defined by an OpenAPI 3.1 schema (vllm-project#16721)
Signed-off-by: Tarun Kumar <[email protected]> Signed-off-by: Nick Hill <[email protected]> Co-authored-by: Nick Hill <[email protected]>
1 parent e7cfb5a commit 07d0eed

File tree

4 files changed

+134
-6
lines changed

4 files changed

+134
-6
lines changed

.buildkite/test-pipeline.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ steps:
118118
- pytest -v -s entrypoints/llm/test_generate.py # it needs a clean process
119119
- pytest -v -s entrypoints/llm/test_generate_multiple_loras.py # it needs a clean process
120120
- VLLM_USE_V1=0 pytest -v -s entrypoints/llm/test_guided_generate.py # it needs a clean process
121-
- pytest -v -s entrypoints/openai --ignore=entrypoints/openai/test_oot_registration.py --ignore=entrypoints/openai/test_chat_with_tool_reasoning.py --ignore=entrypoints/openai/correctness/
121+
- pytest -v -s entrypoints/openai --ignore=entrypoints/openai/test_oot_registration.py --ignore=entrypoints/openai/test_chat_with_tool_reasoning.py --ignore=entrypoints/openai/correctness/ --ignore=entrypoints/openai/test_openai_schema.py
122122
- pytest -v -s entrypoints/test_chat_utils.py
123123
- VLLM_USE_V1=0 pytest -v -s entrypoints/offline_mode # Needs to avoid interference with other tests
124124

requirements/test.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ lm-eval[api]==0.4.8 # required for model evaluation test
3737
transformers==4.51.1
3838
tokenizers==0.21.1
3939
huggingface-hub[hf_xet]>=0.30.0 # Required for Xet downloads.
40+
schemathesis>=3.39.15 # Required for openai schema test.
4041
# quantization
4142
bitsandbytes>=0.45.3
4243
buildkite-test-collector==0.1.9

requirements/test.txt

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,29 @@ aiosignal==1.3.1
2020
annotated-types==0.7.0
2121
# via pydantic
2222
anyio==4.6.2.post1
23-
# via httpx
23+
# via
24+
# httpx
25+
# starlette
2426
argcomplete==3.5.1
2527
# via datamodel-code-generator
28+
arrow==1.3.0
29+
# via isoduration
2630
attrs==24.2.0
2731
# via
2832
# aiohttp
33+
# hypothesis
2934
# jsonlines
3035
# jsonschema
36+
# pytest-subtests
3137
# referencing
3238
audioread==3.0.1
3339
# via librosa
3440
awscli==1.35.23
3541
# via -r requirements/test.in
3642
backoff==2.2.1
37-
# via -r requirements/test.in
43+
# via
44+
# -r requirements/test.in
45+
# schemathesis
3846
bitsandbytes==0.45.3
3947
# via -r requirements/test.in
4048
black==24.10.0
@@ -69,11 +77,13 @@ click==8.1.7
6977
# jiwer
7078
# nltk
7179
# ray
80+
# schemathesis
7281
# typer
7382
colorama==0.4.6
7483
# via
7584
# awscli
7685
# sacrebleu
86+
# schemathesis
7787
# tqdm-multiprocess
7888
contourpy==1.3.0
7989
# via matplotlib
@@ -138,6 +148,8 @@ filelock==3.16.1
138148
# transformers
139149
fonttools==4.54.1
140150
# via matplotlib
151+
fqdn==1.5.1
152+
# via jsonschema
141153
frozendict==2.4.6
142154
# via einx
143155
frozenlist==1.5.0
@@ -156,16 +168,22 @@ genai-perf==0.0.8
156168
# via -r requirements/test.in
157169
genson==1.3.0
158170
# via datamodel-code-generator
171+
graphql-core==3.2.6
172+
# via hypothesis-graphql
159173
h11==0.14.0
160174
# via httpcore
175+
harfile==0.3.0
176+
# via schemathesis
161177
hf-xet==0.1.4
162178
# via huggingface-hub
163179
hiredis==3.0.0
164180
# via tensorizer
165181
httpcore==1.0.6
166182
# via httpx
167183
httpx==0.27.2
168-
# via -r requirements/test.in
184+
# via
185+
# -r requirements/test.in
186+
# schemathesis
169187
huggingface-hub==0.30.1
170188
# via
171189
# -r requirements/test.in
@@ -180,17 +198,29 @@ huggingface-hub==0.30.1
180198
# vocos
181199
humanize==4.11.0
182200
# via runai-model-streamer
201+
hypothesis==6.131.0
202+
# via
203+
# hypothesis-graphql
204+
# hypothesis-jsonschema
205+
# schemathesis
206+
hypothesis-graphql==0.11.1
207+
# via schemathesis
208+
hypothesis-jsonschema==0.23.1
209+
# via schemathesis
183210
idna==3.10
184211
# via
185212
# anyio
186213
# email-validator
187214
# httpx
215+
# jsonschema
188216
# requests
189217
# yarl
190218
inflect==5.6.2
191219
# via datamodel-code-generator
192220
iniconfig==2.0.0
193221
# via pytest
222+
isoduration==20.11.0
223+
# via jsonschema
194224
isort==5.13.2
195225
# via datamodel-code-generator
196226
jinja2==3.1.6
@@ -210,12 +240,18 @@ joblib==1.4.2
210240
# scikit-learn
211241
jsonlines==4.0.0
212242
# via lm-eval
243+
jsonpointer==3.0.0
244+
# via jsonschema
213245
jsonschema==4.23.0
214246
# via
247+
# hypothesis-jsonschema
215248
# mistral-common
216249
# ray
250+
# schemathesis
217251
jsonschema-specifications==2024.10.1
218252
# via jsonschema
253+
junit-xml==1.9
254+
# via schemathesis
219255
kaleido==0.2.1
220256
# via genai-perf
221257
kiwisolver==1.4.7
@@ -239,7 +275,9 @@ mamba-ssm==2.2.4
239275
markdown-it-py==3.0.0
240276
# via rich
241277
markupsafe==3.0.2
242-
# via jinja2
278+
# via
279+
# jinja2
280+
# werkzeug
243281
matplotlib==3.9.2
244282
# via -r requirements/test.in
245283
mbstrdecoder==1.1.3
@@ -449,6 +487,8 @@ pygments==2.18.0
449487
# via rich
450488
pyparsing==3.2.0
451489
# via matplotlib
490+
pyrate-limiter==3.7.0
491+
# via schemathesis
452492
pytablewriter==1.2.0
453493
# via lm-eval
454494
pytest==8.3.3
@@ -461,7 +501,9 @@ pytest==8.3.3
461501
# pytest-mock
462502
# pytest-rerunfailures
463503
# pytest-shard
504+
# pytest-subtests
464505
# pytest-timeout
506+
# schemathesis
465507
pytest-asyncio==0.24.0
466508
# via -r requirements/test.in
467509
pytest-forked==1.6.0
@@ -472,10 +514,13 @@ pytest-rerunfailures==14.0
472514
# via -r requirements/test.in
473515
pytest-shard==0.1.2
474516
# via -r requirements/test.in
517+
pytest-subtests==0.14.1
518+
# via schemathesis
475519
pytest-timeout==2.3.1
476520
# via -r requirements/test.in
477521
python-dateutil==2.9.0.post0
478522
# via
523+
# arrow
479524
# botocore
480525
# matplotlib
481526
# pandas
@@ -497,6 +542,7 @@ pyyaml==6.0.2
497542
# peft
498543
# ray
499544
# responses
545+
# schemathesis
500546
# timm
501547
# transformers
502548
# vocos
@@ -527,10 +573,16 @@ requests==2.32.3
527573
# pooch
528574
# ray
529575
# responses
576+
# schemathesis
577+
# starlette-testclient
530578
# tiktoken
531579
# transformers
532580
responses==0.25.3
533581
# via genai-perf
582+
rfc3339-validator==0.1.4
583+
# via jsonschema
584+
rfc3987==1.3.8
585+
# via jsonschema
534586
rich==13.9.4
535587
# via
536588
# genai-perf
@@ -559,6 +611,8 @@ safetensors==0.4.5
559611
# peft
560612
# timm
561613
# transformers
614+
schemathesis==3.39.15
615+
# via -r requirements/test.in
562616
scikit-learn==1.5.2
563617
# via
564618
# librosa
@@ -584,12 +638,16 @@ shellingham==1.5.4
584638
# via typer
585639
six==1.16.0
586640
# via
641+
# junit-xml
587642
# python-dateutil
643+
# rfc3339-validator
588644
# rouge-score
589645
sniffio==1.3.1
590646
# via
591647
# anyio
592648
# httpx
649+
sortedcontainers==2.4.0
650+
# via hypothesis
593651
soundfile==0.12.1
594652
# via
595653
# -r requirements/test.in
@@ -598,6 +656,12 @@ soxr==0.5.0.post1
598656
# via librosa
599657
sqlitedict==2.1.0
600658
# via lm-eval
659+
starlette==0.46.2
660+
# via
661+
# schemathesis
662+
# starlette-testclient
663+
starlette-testclient==0.4.1
664+
# via schemathesis
601665
statsmodels==0.14.4
602666
# via genai-perf
603667
sympy==1.13.1
@@ -628,6 +692,10 @@ tokenizers==0.21.1
628692
# via
629693
# -r requirements/test.in
630694
# transformers
695+
tomli==2.2.1
696+
# via schemathesis
697+
tomli-w==1.2.0
698+
# via schemathesis
631699
torch==2.6.0
632700
# via
633701
# -r requirements/test.in
@@ -693,6 +761,8 @@ typepy==1.3.2
693761
# tabledata
694762
typer==0.15.2
695763
# via fastsafetensors
764+
types-python-dateutil==2.9.0.20241206
765+
# via arrow
696766
typing-extensions==4.12.2
697767
# via
698768
# huggingface-hub
@@ -705,6 +775,8 @@ typing-extensions==4.12.2
705775
# typer
706776
tzdata==2024.2
707777
# via pandas
778+
uri-template==1.3.0
779+
# via jsonschema
708780
urllib3==2.2.3
709781
# via
710782
# blobfile
@@ -716,13 +788,19 @@ vector-quantize-pytorch==1.21.2
716788
# via -r requirements/test.in
717789
vocos==0.1.0
718790
# via -r requirements/test.in
791+
webcolors==24.11.1
792+
# via jsonschema
793+
werkzeug==3.1.3
794+
# via schemathesis
719795
word2number==1.1
720796
# via lm-eval
721797
xxhash==3.5.0
722798
# via
723799
# datasets
724800
# evaluate
725801
yarl==1.17.1
726-
# via aiohttp
802+
# via
803+
# aiohttp
804+
# schemathesis
727805
zstandard==0.23.0
728806
# via lm-eval
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
import pytest
3+
import schemathesis
4+
from schemathesis import GenerationConfig
5+
6+
from ...utils import RemoteOpenAIServer
7+
8+
schemathesis.experimental.OPEN_API_3_1.enable()
9+
10+
MODEL_NAME = "HuggingFaceTB/SmolVLM-256M-Instruct"
11+
MAXIMUM_IMAGES = 2
12+
13+
14+
@pytest.fixture(scope="module")
15+
def server():
16+
args = [
17+
"--task",
18+
"generate",
19+
"--max-model-len",
20+
"2048",
21+
"--max-num-seqs",
22+
"5",
23+
"--enforce-eager",
24+
"--trust-remote-code",
25+
"--limit-mm-per-prompt",
26+
f"image={MAXIMUM_IMAGES}",
27+
]
28+
29+
with RemoteOpenAIServer(MODEL_NAME, args) as remote_server:
30+
yield remote_server
31+
32+
33+
@pytest.fixture(scope="module")
34+
def get_schema(server):
35+
# avoid generating null (\x00) bytes in strings during test case generation
36+
return schemathesis.openapi.from_uri(
37+
f"{server.url_root}/openapi.json",
38+
generation_config=GenerationConfig(allow_x00=False),
39+
)
40+
41+
42+
schema = schemathesis.from_pytest_fixture("get_schema")
43+
44+
45+
@schema.parametrize()
46+
@schema.override(headers={"Content-Type": "application/json"})
47+
async def test_openapi_stateless(case):
48+
#No need to verify SSL certificate for localhost
49+
await case.call_and_validate(verify=False)

0 commit comments

Comments
 (0)