44import logging
55import os
66import time
7+ from contextlib import ExitStack , contextmanager
78from typing import Any , Callable , ContextManager
89
910from tests .router .common import (
1920
2021logger = logging .getLogger (__name__ )
2122
23+
24+ def env_int (name : str , default : int ) -> int :
25+ return int (os .environ .get (name , default ))
26+
27+
28+ def env_optional_int (name : str ) -> int | None :
29+ raw = os .environ .get (name )
30+ return None if raw is None else int (raw )
31+
32+
33+ def env_float (name : str , default : float ) -> float :
34+ return float (os .environ .get (name , default ))
35+
36+
37+ def env_bool (name : str , default : bool ) -> bool :
38+ raw = os .environ .get (name )
39+ return default if raw is None else raw .lower () not in {"0" , "false" , "no" , "off" }
40+
41+
42+ def resolve_router_gpu_start_index (gpu_start_index : int ) -> int :
43+ override = os .environ .get ("DYNAMO_ROUTER_E2E_GPU_START_INDEX" )
44+ if override is None :
45+ return gpu_start_index
46+ try :
47+ base_index = int (override )
48+ except ValueError as exc :
49+ raise ValueError (
50+ "DYNAMO_ROUTER_E2E_GPU_START_INDEX must be an integer"
51+ ) from exc
52+ return base_index + gpu_start_index
53+
54+
55+ def _resolve_router_e2e_num_requests (default : int = 10 ) -> int :
56+ override = os .environ .get ("DYNAMO_ROUTER_E2E_NUM_REQUESTS" )
57+ if override is None :
58+ return default
59+ try :
60+ value = int (override )
61+ except ValueError as exc :
62+ raise ValueError ("DYNAMO_ROUTER_E2E_NUM_REQUESTS must be an integer" ) from exc
63+ if value <= 0 :
64+ raise ValueError ("DYNAMO_ROUTER_E2E_NUM_REQUESTS must be positive" )
65+ return value
66+
67+
68+ @contextmanager
69+ def maybe_router_gms_servers ():
70+ if os .environ .get ("DYNAMO_ROUTER_E2E_ENABLE_GMS" ) != "1" :
71+ yield
72+ return
73+
74+ from tests .gpu_memory_service .common .gms import GMSServer
75+
76+ devices = os .environ .get ("DYNAMO_ROUTER_E2E_GMS_DEVICES" , "0,1" )
77+ tags = os .environ .get ("DYNAMO_ROUTER_E2E_GMS_TAGS" , "weights,kv_cache" )
78+ device_ids = [int (part .strip ()) for part in devices .split ("," ) if part .strip ()]
79+ tag_names = [part .strip () for part in tags .split ("," ) if part .strip ()]
80+
81+ with ExitStack () as stack :
82+ for device in device_ids :
83+ for tag in tag_names :
84+ stack .enter_context (GMSServer (device = device , tag = tag ))
85+ yield
86+
87+
2288TEST_PROMPT = (
2389 "In a quiet meadow tucked between rolling hills, a plump gray rabbit nibbled on "
2490 "clover beneath the shade of a gnarled oak tree. Its ears twitched at the faint "
@@ -214,15 +280,17 @@ def run_basic_router_test(
214280 },
215281 engine_process_kwargs = engine_process_kwargs ,
216282 )
217- with process as engine_workers :
283+ with ExitStack () as stack :
284+ stack .enter_context (maybe_router_gms_servers ())
285+ engine_workers = stack .enter_context (process )
218286 frontend_port = allocate_frontend_ports (request , 1 )[0 ]
219287 _test_router_basic (
220288 engine_workers = engine_workers ,
221289 block_size = block_size ,
222290 request = request ,
223291 frontend_port = frontend_port ,
224292 test_payload = test_payload or build_test_payload (model_name ),
225- num_requests = num_requests ,
293+ num_requests = _resolve_router_e2e_num_requests ( num_requests ) ,
226294 frontend_timeout = frontend_timeout ,
227295 store_backend = "etcd" ,
228296 request_plane = request_plane ,
@@ -263,7 +331,9 @@ def run_router_decisions_test(
263331 default_process_kwargs = default_process_kwargs ,
264332 engine_process_kwargs = engine_process_kwargs ,
265333 )
266- with process as engine_workers :
334+ with ExitStack () as stack :
335+ stack .enter_context (maybe_router_gms_servers ())
336+ engine_workers = stack .enter_context (process )
267337 endpoint = get_engine_endpoint (engine_workers , request_plane , component_name )
268338 scenario_kwargs = dict (test_kwargs or {})
269339 for argument , attribute in (
@@ -302,6 +372,7 @@ def run_disagg_router_decisions_test(
302372 | None = None ,
303373 test_payload : dict [str , Any ] | None = None ,
304374 test_kwargs : dict [str , Any ] | None = None ,
375+ strict_timing : bool = True ,
305376):
306377 shared_namespace = f"test-namespace-{ generate_random_suffix ()} "
307378 frontend_port = allocate_frontend_ports (request , 1 )[0 ]
@@ -316,6 +387,7 @@ def run_disagg_router_decisions_test(
316387 }
317388
318389 def run_test (prefill_workers , decode_workers ):
390+ scenario_kwargs = {"strict_timing" : strict_timing , ** (test_kwargs or {})}
319391 _test_router_decisions_disagg (
320392 prefill_workers = prefill_workers ,
321393 decode_workers = decode_workers ,
@@ -324,29 +396,35 @@ def run_test(prefill_workers, decode_workers):
324396 frontend_port = frontend_port ,
325397 test_payload = test_payload or build_test_payload (model_name ),
326398 request_plane = request_plane ,
327- ** ( test_kwargs or {}) ,
399+ ** scenario_kwargs ,
328400 )
329401
330- if worker_context_factory is not None :
331- with worker_context_factory (shared_namespace ) as workers :
402+ with ExitStack () as stack :
403+ stack .enter_context (maybe_router_gms_servers ())
404+ if worker_context_factory is not None :
405+ workers = stack .enter_context (worker_context_factory (shared_namespace ))
332406 run_test (* workers )
333- return
334-
335- with engine_process_cls (
336- request ,
337- num_workers = num_prefill_workers ,
338- request_plane = request_plane ,
339- ** {engine_args_name : engine_args },
340- ** prefill_kwargs ,
341- ) as prefill_workers :
342- with engine_process_cls (
343- request ,
344- num_workers = num_decode_workers ,
345- request_plane = request_plane ,
346- ** {engine_args_name : engine_args },
347- ** decode_kwargs ,
348- ) as decode_workers :
349- run_test (prefill_workers , decode_workers )
407+ return
408+
409+ prefill_workers = stack .enter_context (
410+ engine_process_cls (
411+ request ,
412+ num_workers = num_prefill_workers ,
413+ request_plane = request_plane ,
414+ ** {engine_args_name : engine_args },
415+ ** prefill_kwargs ,
416+ )
417+ )
418+ decode_workers = stack .enter_context (
419+ engine_process_cls (
420+ request ,
421+ num_workers = num_decode_workers ,
422+ request_plane = request_plane ,
423+ ** {engine_args_name : engine_args },
424+ ** decode_kwargs ,
425+ )
426+ )
427+ run_test (prefill_workers , decode_workers )
350428
351429
352430def run_indexers_sync_test (
@@ -383,7 +461,9 @@ def run_indexers_sync_test(
383461 },
384462 engine_process_kwargs = engine_process_kwargs ,
385463 )
386- with process as engine_workers :
464+ with ExitStack () as stack :
465+ stack .enter_context (maybe_router_gms_servers ())
466+ engine_workers = stack .enter_context (process )
387467 _test_router_indexers_sync (
388468 engine_workers = engine_workers ,
389469 block_size = block_size ,
0 commit comments