Skip to content

Commit 729e95f

Browse files
committed
[integration_test] drop dev-machine assumptions from the vllm e2e harness
- delete the immature test-vllm-e2e workflow (runner/model/venv/uv are all dev-machine specific); e2e CI will land as a separate PR - KVCM_E2E_MODEL / KVCM_E2E_PYTHON become required env vars with clear errors instead of local-path defaults - remove the unused cosine-similarity fallback: every scenario is verified bit-exact - tag the e2e targets manual (GPU + vLLM venv + model required) and add an explicit :e2e_tests suite - document all environment variables in the README
1 parent 4052b4c commit 729e95f

5 files changed

Lines changed: 114 additions & 179 deletions

File tree

.github/workflows/test-vllm-e2e.yml

Lines changed: 0 additions & 111 deletions
This file was deleted.

integration_test/vllm_e2e/BUILD

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,130 +14,155 @@ py_library(
1414

1515
py_test(
1616
name = "test_basic",
17+
timeout = "eternal",
1718
srcs = ["test_basic.py"],
1819
data = [
1920
"//kv_cache_manager:kv_cache_manager_bin",
2021
],
2122
imports = ["."],
2223
tags = [
23-
"no-remote-exec",
24-
"gpu", # requires 1+ GPU
2524
"exclusive", # GPU tests must run serially to avoid CUDA OOM contention
25+
"gpu", # requires 1+ GPU
26+
"manual", # needs a GPU machine + vLLM venv + model; see README.md
27+
"no-remote-exec",
2628
],
27-
timeout = "eternal",
2829
deps = [":e2e_lib"],
2930
)
3031

3132
py_test(
3233
name = "test_concurrent",
34+
timeout = "eternal",
3335
srcs = ["test_concurrent.py"],
3436
data = [
3537
"//kv_cache_manager:kv_cache_manager_bin",
3638
],
3739
imports = ["."],
3840
tags = [
39-
"no-remote-exec",
40-
"gpu", # requires 1+ GPU
4141
"exclusive", # GPU tests must run serially to avoid CUDA OOM contention
42+
"gpu", # requires 1+ GPU
43+
"manual", # needs a GPU machine + vLLM venv + model; see README.md
44+
"no-remote-exec",
4245
],
43-
timeout = "eternal",
4446
deps = [":e2e_lib"],
4547
)
4648

4749
py_test(
4850
name = "test_tp",
51+
timeout = "eternal",
4952
srcs = ["test_tp.py"],
5053
data = [
5154
"//kv_cache_manager:kv_cache_manager_bin",
5255
],
5356
imports = ["."],
5457
tags = [
55-
"no-remote-exec",
56-
"gpu", # requires 1+ GPU
5758
"exclusive", # GPU tests must run serially to avoid CUDA OOM contention
59+
"gpu", # requires 1+ GPU
60+
"manual", # needs a GPU machine + vLLM venv + model; see README.md
61+
"no-remote-exec",
5862
],
59-
timeout = "eternal",
6063
deps = [":e2e_lib"],
6164
)
6265

6366
py_test(
6467
name = "test_full_hit",
68+
timeout = "eternal",
6569
srcs = ["test_full_hit.py"],
6670
data = [
6771
"//kv_cache_manager:kv_cache_manager_bin",
6872
],
6973
imports = ["."],
7074
tags = [
71-
"no-remote-exec",
72-
"gpu", # requires 1+ GPU
7375
"exclusive", # GPU tests must run serially to avoid CUDA OOM contention
76+
"gpu", # requires 1+ GPU
77+
"manual", # needs a GPU machine + vLLM venv + model; see README.md
78+
"no-remote-exec",
7479
],
75-
timeout = "eternal",
7680
deps = [":e2e_lib"],
7781
)
7882

7983
py_test(
8084
name = "test_partial_hit",
85+
timeout = "eternal",
8186
srcs = ["test_partial_hit.py"],
8287
data = [
8388
"//kv_cache_manager:kv_cache_manager_bin",
8489
],
8590
imports = ["."],
8691
tags = [
87-
"no-remote-exec",
88-
"gpu", # requires 1+ GPU
8992
"exclusive", # GPU tests must run serially to avoid CUDA OOM contention
93+
"gpu", # requires 1+ GPU
94+
"manual", # needs a GPU machine + vLLM venv + model; see README.md
95+
"no-remote-exec",
9096
],
91-
timeout = "eternal",
9297
deps = [":e2e_lib"],
9398
)
9499

95100
py_test(
96101
name = "test_load_failure",
102+
timeout = "eternal",
97103
srcs = ["test_load_failure.py"],
98104
data = [
99105
"//kv_cache_manager:kv_cache_manager_bin",
100106
],
101107
imports = ["."],
102108
tags = [
103-
"no-remote-exec",
104-
"gpu", # requires 1+ GPU
105109
"exclusive", # GPU tests must run serially to avoid CUDA OOM contention
110+
"gpu", # requires 1+ GPU
111+
"manual", # needs a GPU machine + vLLM venv + model; see README.md
112+
"no-remote-exec",
106113
],
107-
timeout = "eternal",
108114
deps = [":e2e_lib"],
109115
)
110116

111117
py_test(
112118
name = "test_multi_turn",
119+
timeout = "eternal",
113120
srcs = ["test_multi_turn.py"],
114121
data = [
115122
"//kv_cache_manager:kv_cache_manager_bin",
116123
],
117124
imports = ["."],
118125
tags = [
119-
"no-remote-exec",
120-
"gpu", # requires 1+ GPU
121126
"exclusive", # GPU tests must run serially to avoid CUDA OOM contention
127+
"gpu", # requires 1+ GPU
128+
"manual", # needs a GPU machine + vLLM venv + model; see README.md
129+
"no-remote-exec",
122130
],
123-
timeout = "eternal",
124131
deps = [":e2e_lib"],
125132
)
126133

127134
# Meta-test: injects an off-by-one into the connector's token translation and
128135
# asserts the KV verification FAILS -- proof the harness is not vacuous.
129136
py_test(
130137
name = "test_mutation",
138+
timeout = "eternal",
131139
srcs = ["test_mutation.py"],
132140
data = [
133141
"//kv_cache_manager:kv_cache_manager_bin",
134142
],
135143
imports = ["."],
136144
tags = [
137-
"no-remote-exec",
138-
"gpu", # requires 1+ GPU
139145
"exclusive", # GPU tests must run serially to avoid CUDA OOM contention
146+
"gpu", # requires 1+ GPU
147+
"manual", # needs a GPU machine + vLLM venv + model; see README.md
148+
"no-remote-exec",
140149
],
141-
timeout = "eternal",
142150
deps = [":e2e_lib"],
143151
)
152+
153+
# Wildcards skip "manual" targets; run the whole suite explicitly with
154+
# bazelisk test //integration_test/vllm_e2e:e2e_tests
155+
test_suite(
156+
name = "e2e_tests",
157+
tags = ["manual"], # keep wildcard builds from expanding into the GPU tests
158+
tests = [
159+
":test_basic",
160+
":test_concurrent",
161+
":test_full_hit",
162+
":test_load_failure",
163+
":test_multi_turn",
164+
":test_mutation",
165+
":test_partial_hit",
166+
":test_tp",
167+
],
168+
)

integration_test/vllm_e2e/README.md

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ block-table mapping:
2929
2. **Phase 2** — same prompts + suffix: connector reports an external match and
3030
loads from KVCM. The loaded blocks are captured (**loaded** captures).
3131
3. The driver (`e2e_lib.py`) matches loaded captures against references by
32-
token content and compares per layer: bit-exact preferred, cosine
33-
similarity > 99.99% as fallback.
32+
token content and compares per layer, requiring bit-exact equality (the
33+
transfer is a verbatim byte round trip; all scenarios achieve it).
3434

3535
## Model coverage
3636

@@ -56,9 +56,18 @@ Hybrid specifics verified:
5656
| `test_basic` | 1 | 1 | Minimal save -> load round trip |
5757
| `test_concurrent` | 1 | 4 | Concurrent requests: ReqState tracking, per-request block attribution |
5858
| `test_tp` | 2 | 2 | TP coordination; for full-attention models also `preferred_block_size=32` != vLLM block size (16), forcing real cross-block translation |
59+
| `test_partial_hit` | 1 | 1 | Phase 2 extends the prompt mid-block: partial external hit |
60+
| `test_full_hit` | 1 | 1 | Phase 2 resends the identical prompt: full-prompt hit is capped so >= 1 token is recomputed |
61+
| `test_multi_turn` | 1 | 1 | Growing conversation: each turn loads the previous turns' blocks and saves new ones |
62+
| `test_load_failure` | 1 | 1 | Storage files deleted between phases: load fails, retry loop must not spin, request still completes |
63+
| `test_mutation` | 1 | 1 | Meta-test: injected off-by-one in the slot translation must make verification FAIL (proves the harness is not vacuous) |
5964

6065
## Running
6166

67+
These targets are tagged `manual`: they need a GPU machine with a prepared
68+
vLLM venv and a local model, so `bazelisk test //integration_test/...` skips
69+
them and they must be requested explicitly (see below).
70+
6271
Build prerequisites (from the repo root):
6372

6473
```bash
@@ -75,19 +84,27 @@ from the wheel's `METADATA`).
7584
Run (tagged `exclusive`, so they execute serially):
7685

7786
```bash
78-
bazelisk test //integration_test/vllm_e2e/... \
87+
bazelisk test //integration_test/vllm_e2e:e2e_tests \
7988
--cache_test_results=no --test_output=errors \
8089
--test_env=KVCM_E2E_PYTHON=/path/to/vllm-venv/bin/python \
8190
--test_env=KVCM_E2E_MODEL=/path/to/model \
8291
--per_file_copt='external/jsoncpp_git/.*@-Wno-error'
8392
```
8493

85-
Environment variables:
94+
## Environment variables
95+
96+
All environment variables used by the e2e harness:
97+
98+
| Variable | Required | Meaning |
99+
|---|---|---|
100+
| `KVCM_E2E_MODEL` | yes | Path to a local HF model directory (`config.json` + weights). Full-attention coverage needs a plain attention model (e.g. Qwen2.5-7B-Instruct); hybrid coverage needs a mamba/linear + attention model (e.g. Qwen3.5-4B). Hybrid models are auto-detected from `config.json`. |
101+
| `KVCM_E2E_PYTHON` | yes | Python interpreter of a venv with vLLM >= 0.26.0 and both KVCM wheels (`kvcm_py_client`, `kvcm_vllm_connector`) installed. |
102+
| `KVCM_E2E_CAPTURE_DIR` | internal | Set by the driver for the vLLM subprocess; tells `VerifyingConnector` where to write `.pt` captures. Do not set manually. |
86103

87-
| Variable | Meaning |
88-
|---|---|
89-
| `KVCM_E2E_PYTHON` | Python interpreter with vLLM + both KVCM wheels installed |
90-
| `KVCM_E2E_MODEL` | Model path; hybrid models are auto-detected from `config.json` |
104+
The driver also sets vLLM knobs for the spawned server (`VLLM_KV_CACHE_LAYOUT=NHD`,
105+
`VLLM_ATTENTION_BACKEND=FLASH_ATTN`, `VLLM_USE_FLASHINFER_SAMPLER=0`,
106+
`FLASHINFER_DISABLE_VERSION_CHECK=1`) via `env.setdefault`, so a value you
107+
export yourself wins.
91108

92109
## Debugging
93110

0 commit comments

Comments
 (0)