Signed-off-by: srinivas_oo7 <sklinkedin0120@gmail.com> Co-authored-by: srinivas_oo7 <sklinkedin0120@gmail.com> Co-authored-by: Zhou Taichang <tzhouam@connect.ust.hk>
168 lines
4.7 KiB
Python
168 lines
4.7 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
|
"""Route-level tests for RL rollout serving endpoints."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
from fastapi import FastAPI
|
|
from fastapi.testclient import TestClient
|
|
|
|
from vllm_omni.entrypoints.openai.api_server import router
|
|
from vllm_omni.entrypoints.openai.protocol.rollout import (
|
|
ErrorObject,
|
|
RolloutStepResponse,
|
|
SessionMetadata,
|
|
)
|
|
from vllm_omni.entrypoints.openai.rollout_session import (
|
|
RolloutSessionClosedError,
|
|
RolloutSessionNotFoundError,
|
|
)
|
|
|
|
|
|
class _FakeRolloutServing:
|
|
def __init__(self, close_error: Exception | None = None, step_error_code: str | None = None) -> None:
|
|
self.close_error = close_error
|
|
self.step_error_code = step_error_code
|
|
self.step_request = None
|
|
|
|
async def step(self, session_id, body):
|
|
self.step_request = body
|
|
error = None
|
|
if self.step_error_code is not None:
|
|
error = ErrorObject(
|
|
code=self.step_error_code,
|
|
message=f"{self.step_error_code}: {session_id}",
|
|
step_id=body.step_id,
|
|
committed_step_id=-1,
|
|
)
|
|
return RolloutStepResponse(
|
|
step_id=body.step_id,
|
|
next_observation=None,
|
|
model_metadata=SessionMetadata(
|
|
latency_ms=0.0,
|
|
steps_generated=0,
|
|
context_length=0,
|
|
committed_step_id=-1,
|
|
),
|
|
error=error,
|
|
)
|
|
|
|
async def close_session(self, session_id):
|
|
if self.close_error is not None:
|
|
raise self.close_error
|
|
|
|
|
|
def _client(serving: _FakeRolloutServing | None = None) -> TestClient:
|
|
app = FastAPI()
|
|
app.include_router(router)
|
|
if serving is not None:
|
|
app.state.rl_rollout_serving = serving
|
|
return TestClient(app)
|
|
|
|
|
|
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
|
|
|
|
|
def test_step_route_rejects_base64_image_payload():
|
|
serving = _FakeRolloutServing()
|
|
client = _client(serving)
|
|
|
|
response = client.post(
|
|
"/v1/realtime/sessions/s1/step",
|
|
json={
|
|
"step_id": 0,
|
|
"observation": {"images": {"front": "base64-frames"}},
|
|
"action": {},
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 422
|
|
assert serving.step_request is None
|
|
|
|
|
|
def test_step_route_accepts_nested_image_payload():
|
|
serving = _FakeRolloutServing()
|
|
client = _client(serving)
|
|
|
|
response = client.post(
|
|
"/v1/realtime/sessions/s1/step",
|
|
json={
|
|
"step_id": 0,
|
|
"observation": {"images": {"observation/exterior_image_1_left": [[[0, 0, 0]]]}},
|
|
"action": {},
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
assert serving.step_request.observation.images == {"observation/exterior_image_1_left": [[[0, 0, 0]]]}
|
|
|
|
|
|
def test_step_route_requires_action():
|
|
client = _client(_FakeRolloutServing())
|
|
|
|
response = client.post(
|
|
"/v1/realtime/sessions/s1/step",
|
|
json={"step_id": 0, "observation": {}},
|
|
)
|
|
|
|
assert response.status_code == 422
|
|
|
|
|
|
def test_step_route_maps_missing_session_to_404():
|
|
client = _client(_FakeRolloutServing(step_error_code="session_not_found"))
|
|
|
|
response = client.post(
|
|
"/v1/realtime/sessions/s1/step",
|
|
json={"step_id": 0, "observation": {}, "action": {}},
|
|
)
|
|
|
|
assert response.status_code == 404
|
|
|
|
|
|
def test_step_route_maps_closed_session_to_410():
|
|
client = _client(_FakeRolloutServing(step_error_code="session_closed"))
|
|
|
|
response = client.post(
|
|
"/v1/realtime/sessions/s1/step",
|
|
json={"step_id": 0, "observation": {}, "action": {}},
|
|
)
|
|
|
|
assert response.status_code == 410
|
|
|
|
|
|
def test_step_route_maps_invalid_request_to_400():
|
|
client = _client(_FakeRolloutServing(step_error_code="invalid_request"))
|
|
|
|
response = client.post(
|
|
"/v1/realtime/sessions/s1/step",
|
|
json={"step_id": 0, "observation": {}, "action": {}},
|
|
)
|
|
|
|
assert response.status_code == 400
|
|
|
|
|
|
def test_close_route_maps_missing_session_to_404():
|
|
client = _client(_FakeRolloutServing(close_error=RolloutSessionNotFoundError("s1")))
|
|
|
|
response = client.post("/v1/realtime/sessions/s1/close")
|
|
|
|
assert response.status_code == 404
|
|
|
|
|
|
def test_close_route_is_idempotent_for_closed_session():
|
|
client = _client(_FakeRolloutServing(close_error=RolloutSessionClosedError("s1")))
|
|
|
|
response = client.post("/v1/realtime/sessions/s1/close")
|
|
|
|
assert response.status_code == 200
|
|
assert response.json()["closed"] is True
|
|
|
|
|
|
def test_rollout_routes_return_501_when_serving_is_unavailable():
|
|
client = _client()
|
|
|
|
response = client.post("/v1/realtime/sessions/s1/close")
|
|
|
|
assert response.status_code == 501
|