项目文件夹

文件
wehub-resource-sync eec33d25b2
Build Wheel / build (3.11) (push) Failing after 1s
Build Wheel / build (3.12) (push) Failing after 0s
pre-commit / pre-commit (push) Failing after 1s
chore: import upstream snapshot with attribution
2026-07-13 12:29:08 +08:00

318 行
10 KiB
Python

import asyncio
from unittest.mock import AsyncMock, MagicMock
import numpy as np
import pytest
from vllm_omni.entrypoints.openpi import connection as openpi_connection
from vllm_omni.entrypoints.openpi.serving import PolicyServerConfig
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
class FakeWebSocket:
def __init__(self, messages):
self._messages = list(messages)
self.sent_bytes = []
self.sent_texts = []
self.accepted = False
self.closed = False
async def accept(self):
self.accepted = True
async def send_bytes(self, data):
self.sent_bytes.append(data)
async def send_text(self, data):
self.sent_texts.append(data)
async def receive(self):
return self._messages.pop(0)
async def close(self):
self.closed = True
def _serving_mock():
serving = MagicMock()
serving.policy_server_config = PolicyServerConfig(
{
"image_resolution": (180, 320),
"n_external_cameras": 2,
"needs_wrist_camera": True,
"needs_stereo_camera": False,
"needs_session_id": True,
"action_space": "joint_position",
}
)
serving.infer = AsyncMock(return_value=[0.0])
return serving
def test_pack_and_unpack_round_trip_numpy_values():
payload = {
"image": np.arange(6, dtype=np.uint8).reshape(2, 3),
"action": np.asarray([[1.0, 2.0]], dtype=np.float32),
"scalar": np.float32(3.5),
"nested": [{"done": np.bool_(True)}],
}
decoded = openpi_connection._unpack(openpi_connection._pack(payload))
np.testing.assert_array_equal(decoded["image"], payload["image"])
np.testing.assert_allclose(decoded["action"], payload["action"])
assert decoded["image"].dtype == np.uint8
assert decoded["action"].dtype == np.float32
assert decoded["scalar"] == np.float32(3.5)
assert decoded["nested"][0]["done"] == np.bool_(True)
def test_unpack_accepts_msgpack_numpy_marker_dicts():
action = np.asarray([[1.0, 2.0]], dtype=np.float32)
payload = {
b"actions": {
b"nd": True,
b"type": action.dtype.str,
b"kind": action.dtype.kind,
b"shape": action.shape,
b"data": action.tobytes(),
}
}
decoded = openpi_connection._unpack_numpy(payload)
np.testing.assert_allclose(decoded[b"actions"], action)
assert decoded[b"actions"].flags.writeable is True
decoded[b"actions"][:, -1] = 0.0
np.testing.assert_allclose(decoded[b"actions"], np.asarray([[1.0, 0.0]], dtype=np.float32))
def test_unpack_accepts_openpi_client_ndarray_markers():
image = np.arange(6, dtype=np.uint8).reshape(2, 3)
payload = {
"observation/exterior_image_0_left": {
b"__ndarray__": True,
b"dtype": image.dtype.str,
b"shape": image.shape,
b"data": image.tobytes(),
}
}
decoded = openpi_connection._unpack_numpy(payload)
np.testing.assert_array_equal(decoded["observation/exterior_image_0_left"], image)
assert decoded["observation/exterior_image_0_left"].dtype == np.uint8
def test_unpack_openpi_client_packed_observation():
openpi_msgpack = pytest.importorskip("openpi_client.msgpack_numpy")
image = np.zeros((180, 320, 3), dtype=np.uint8)
obs = {
"observation/exterior_image_0_left": image,
"observation/joint_position": np.zeros(7, dtype=np.float32),
}
decoded = openpi_connection._unpack(openpi_msgpack.packb(obs))
np.testing.assert_array_equal(decoded["observation/exterior_image_0_left"], image)
np.testing.assert_allclose(decoded["observation/joint_position"], obs["observation/joint_position"])
def test_pack_uses_openpi_client_ndarray_markers():
openpi_msgpack = pytest.importorskip("openpi_client.msgpack_numpy")
actions = np.asarray([[1.0, 2.0]], dtype=np.float32)
packed = openpi_connection._pack(actions)
decoded = openpi_msgpack.unpackb(packed)
np.testing.assert_allclose(decoded, actions)
def test_unpack_leaves_user_dict_without_numpy_kind_marker_unchanged():
payload = {
"metadata": {
"nd": True,
"type": "<f4",
"data": b"user payload",
}
}
decoded = openpi_connection._unpack_numpy(payload)
assert decoded == payload
def test_handle_connection_returns_structured_error_for_invalid_payload(monkeypatch):
monkeypatch.setattr(openpi_connection, "_pack", lambda obj: obj)
monkeypatch.setattr(
openpi_connection,
"_unpack",
lambda _data: (_ for _ in ()).throw(ValueError("bad payload traceback")),
)
websocket = FakeWebSocket(
[
{"type": "websocket.receive", "bytes": b"bad"},
{"type": "websocket.disconnect"},
]
)
serving = MagicMock()
connection = openpi_connection.RobotRealtimeConnection(websocket, serving)
asyncio.run(connection.handle_connection())
assert websocket.accepted is True
assert websocket.sent_bytes[1] == {"type": "error", "message": "Invalid request payload"}
assert "traceback" not in str(websocket.sent_bytes[1]).lower()
assert websocket.sent_texts == []
serving.infer.assert_not_called()
serving.reset.assert_not_called()
def test_handle_connection_rejects_oversized_payload_before_unpack(monkeypatch):
unpack_mock = MagicMock(side_effect=AssertionError("_unpack should not be called"))
monkeypatch.setattr(openpi_connection, "_pack", lambda obj: obj)
monkeypatch.setattr(openpi_connection, "_unpack", unpack_mock)
monkeypatch.setattr(openpi_connection, "MAX_OPENPI_PAYLOAD_BYTES", 4)
websocket = FakeWebSocket(
[
{"type": "websocket.receive", "bytes": b"too-large"},
{"type": "websocket.disconnect"},
]
)
serving = MagicMock()
connection = openpi_connection.RobotRealtimeConnection(websocket, serving)
asyncio.run(connection.handle_connection())
assert websocket.sent_bytes[1] == {"type": "error", "message": "Invalid request payload"}
unpack_mock.assert_not_called()
serving.infer.assert_not_called()
serving.reset.assert_not_called()
def test_handle_connection_returns_structured_error_for_infer_exception(monkeypatch):
monkeypatch.setattr(openpi_connection, "_pack", lambda obj: obj)
monkeypatch.setattr(
openpi_connection,
"_unpack",
lambda _data: {"prompt": "pick up the object"},
)
websocket = FakeWebSocket(
[
{"type": "websocket.receive", "bytes": b"request"},
{"type": "websocket.disconnect"},
]
)
serving = MagicMock()
serving.infer = AsyncMock(side_effect=RuntimeError("secret traceback text"))
connection = openpi_connection.RobotRealtimeConnection(websocket, serving)
asyncio.run(connection.handle_connection())
assert websocket.sent_bytes[1] == {"type": "error", "message": "Internal inference error"}
assert "secret traceback text" not in str(websocket.sent_bytes[1])
assert websocket.sent_texts == []
serving.infer.assert_awaited_once_with(
{"prompt": "pick up the object"},
session_id="default",
reset=True,
)
def test_handle_connection_closes_websocket_on_idle_timeout(monkeypatch):
monkeypatch.setattr(openpi_connection, "_pack", lambda obj: obj)
websocket = FakeWebSocket([])
async def never_receives():
await asyncio.sleep(1)
websocket.receive = never_receives
serving = MagicMock()
serving.policy_server_config = PolicyServerConfig(
{
"image_resolution": (180, 320),
"n_external_cameras": 2,
"needs_wrist_camera": True,
"needs_stereo_camera": False,
"needs_session_id": True,
"action_space": "joint_position",
}
)
connection = openpi_connection.RobotRealtimeConnection(
websocket,
serving,
idle_timeout=0.01,
)
asyncio.run(connection.handle_connection())
assert websocket.accepted is True
assert websocket.sent_bytes[0]["action_space"] == "joint_position"
assert websocket.closed is True
assert websocket.sent_texts == []
serving.infer.assert_not_called()
def test_handle_connection_keeps_session_state_per_websocket(monkeypatch):
monkeypatch.setattr(openpi_connection, "_pack", lambda obj: obj)
requests = {
b"a1": {"prompt": "first", "session_id": "session-a"},
b"a2": {"prompt": "second", "session_id": "session-a"},
b"b1": {"prompt": "other", "session_id": "session-b"},
}
monkeypatch.setattr(openpi_connection, "_unpack", lambda data: dict(requests[data]))
serving = _serving_mock()
websocket_a = FakeWebSocket(
[
{"type": "websocket.receive", "bytes": b"a1"},
{"type": "websocket.receive", "bytes": b"a2"},
{"type": "websocket.disconnect"},
]
)
websocket_b = FakeWebSocket(
[
{"type": "websocket.receive", "bytes": b"b1"},
{"type": "websocket.disconnect"},
]
)
asyncio.run(openpi_connection.RobotRealtimeConnection(websocket_a, serving).handle_connection())
asyncio.run(openpi_connection.RobotRealtimeConnection(websocket_b, serving).handle_connection())
calls = serving.infer.await_args_list
assert calls[0].kwargs == {"session_id": "session-a", "reset": True}
assert calls[1].kwargs == {"session_id": "session-a", "reset": False}
assert calls[2].kwargs == {"session_id": "session-b", "reset": True}
def test_handle_connection_reset_endpoint_resets_next_infer(monkeypatch):
monkeypatch.setattr(openpi_connection, "_pack", lambda obj: obj)
requests = {
b"a1": {"prompt": "first", "session_id": "session-a"},
b"reset": {"endpoint": "reset"},
b"a2": {"prompt": "second", "session_id": "session-a"},
}
monkeypatch.setattr(openpi_connection, "_unpack", lambda data: dict(requests[data]))
serving = _serving_mock()
websocket = FakeWebSocket(
[
{"type": "websocket.receive", "bytes": b"a1"},
{"type": "websocket.receive", "bytes": b"reset"},
{"type": "websocket.receive", "bytes": b"a2"},
{"type": "websocket.disconnect"},
]
)
asyncio.run(openpi_connection.RobotRealtimeConnection(websocket, serving).handle_connection())
assert [call.kwargs["reset"] for call in serving.infer.await_args_list] == [True, True]
serving.reset.assert_called_once_with({})
assert websocket.sent_bytes[2] == {"status": "reset successful"}
assert websocket.sent_texts == []