Co-authored-by: ishandhanani <82981111+ishandhanani@users.noreply.github.com>
128 lines
3.6 KiB
Python
128 lines
3.6 KiB
Python
import asyncio
|
|
import enum
|
|
import unittest
|
|
from types import SimpleNamespace
|
|
|
|
from sglang.srt.entrypoints.grpc_bridge import RuntimeHandle
|
|
from sglang.test.ci.ci_register import register_cpu_ci
|
|
from sglang.test.test_utils import CustomTestCase
|
|
|
|
register_cpu_ci(est_time=10, suite="base-a-test-cpu")
|
|
|
|
|
|
class _ChunkStatus(enum.Enum):
|
|
Ready = 1
|
|
Pending = 2
|
|
Closed = 3
|
|
|
|
|
|
class _RecordingCallback:
|
|
def __init__(self):
|
|
self.calls = []
|
|
|
|
def __call__(self, payload, *, finished=False, error=None):
|
|
self.calls.append((payload, finished, error))
|
|
return _ChunkStatus.Ready
|
|
|
|
|
|
class _FakeTokenizerManager:
|
|
def __init__(self, responses):
|
|
self.responses = responses
|
|
|
|
def generate_request(self, obj, request=None):
|
|
async def generate():
|
|
for response in self.responses:
|
|
yield response
|
|
|
|
return generate()
|
|
|
|
|
|
def _make_runtime_handle(responses):
|
|
handle = RuntimeHandle.__new__(RuntimeHandle)
|
|
handle.tokenizer_manager = _FakeTokenizerManager(responses)
|
|
return handle
|
|
|
|
|
|
class TestNativeGrpcReadiness(CustomTestCase):
|
|
def test_readiness_comes_from_tokenizer_manager(self):
|
|
tokenizer_manager = SimpleNamespace(is_ready=lambda: True)
|
|
handle = RuntimeHandle.__new__(RuntimeHandle)
|
|
handle.tokenizer_manager = tokenizer_manager
|
|
|
|
self.assertTrue(handle.get_is_ready())
|
|
|
|
tokenizer_manager.is_ready = lambda: False
|
|
self.assertFalse(handle.get_is_ready())
|
|
|
|
|
|
class TestNativeGrpcParallelResponses(CustomTestCase):
|
|
def test_non_streaming_returns_every_choice_before_finishing(self):
|
|
callback = _RecordingCallback()
|
|
responses = [
|
|
[
|
|
{"output_ids": [1], "meta_info": {"id": "choice-0"}},
|
|
{"output_ids": [2], "meta_info": {"id": "choice-1"}},
|
|
]
|
|
]
|
|
handle = _make_runtime_handle(responses)
|
|
obj = SimpleNamespace(rid="logical", batch_size=1, parallel_sample_num=2)
|
|
|
|
asyncio.run(
|
|
handle._run_generate(
|
|
obj,
|
|
callback,
|
|
stream=False,
|
|
request=None,
|
|
)
|
|
)
|
|
|
|
self.assertEqual([call[0]["output_ids"] for call in callback.calls], [[1], [2]])
|
|
self.assertEqual([call[1] for call in callback.calls], [False, True])
|
|
|
|
def test_streaming_first_finished_choice_is_not_batch_terminal(self):
|
|
callback = _RecordingCallback()
|
|
responses = [
|
|
{
|
|
"index": 0,
|
|
"output_ids": [1],
|
|
"meta_info": {"id": "choice-0", "finish_reason": None},
|
|
},
|
|
{
|
|
"index": 0,
|
|
"output_ids": [2],
|
|
"meta_info": {
|
|
"id": "choice-0",
|
|
"finish_reason": {"type": "stop"},
|
|
},
|
|
},
|
|
{
|
|
"index": 1,
|
|
"output_ids": [3],
|
|
"meta_info": {
|
|
"id": "choice-1",
|
|
"finish_reason": {"type": "stop"},
|
|
},
|
|
},
|
|
]
|
|
handle = _make_runtime_handle(responses)
|
|
obj = SimpleNamespace(rid="logical", sampling_params={"n": 2})
|
|
|
|
asyncio.run(
|
|
handle._run_generate(
|
|
obj,
|
|
callback,
|
|
stream=True,
|
|
request=None,
|
|
)
|
|
)
|
|
|
|
self.assertEqual(
|
|
[call[0]["output_ids"] for call in callback.calls],
|
|
[[1], [2], [3]],
|
|
)
|
|
self.assertEqual([call[1] for call in callback.calls], [False, False, True])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main(verbosity=2)
|