Files
vllm-omni/tests/rl_rollout/test_rollout_routes.py
T
2026-09-14 09:26:44 +08:00

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