chore: fixed sending stuff to ui

This commit is contained in:
JobvAlewijk
2026-01-06 14:52:53 +01:00
parent a96e332d63
commit 128e9b3c00
2 changed files with 96 additions and 118 deletions

View File

@@ -78,7 +78,8 @@ async def get_available_gesture_tags(request: Request, count=0):
amount = count or None
timeout = 5 # seconds
await req_socket.send(f"{amount}".encode() if amount else b"None")
await req_socket.send_json({"type": "tags", "count": amount})
try:
body = await asyncio.wait_for(req_socket.recv(), timeout=timeout)
except TimeoutError:
@@ -94,7 +95,7 @@ async def get_available_gesture_tags(request: Request, count=0):
logger.error(f"Failed to parse gesture tags JSON: {e}, body: {body}")
# Return empty list on JSON error
available_tags = []
return {"available_gesture_tags": available_tags}
return {"available_gestures": available_tags}
@router.get("/commands/gesture/single")

View File

@@ -229,120 +229,60 @@ async def test_ping_stream_yields_json_values(monkeypatch):
mock_sub_socket.recv_multipart.assert_awaited()
# ----------------------------
# Updated get_available_gesture_tags tests (REQ socket on tcp://localhost:7788)
# ----------------------------
@pytest.mark.asyncio
async def test_get_available_gesture_tags_success(client, monkeypatch):
async def test_get_available_single_gestures_success(client, monkeypatch):
"""
Test successful retrieval of available gesture tags using a REQ socket.
Test successful retrieval of single gestures.
"""
# Arrange
mock_req_socket = AsyncMock(spec=zmq.asyncio.Socket)
mock_req_socket.connect = MagicMock()
mock_req_socket.send = AsyncMock()
response_data = {"tags": ["wave", "nod", "point", "dance"]}
mock_req_socket.send_json = AsyncMock()
response_data = {"single_gestures": ["wave", "point"]}
mock_req_socket.recv = AsyncMock(return_value=json.dumps(response_data).encode())
mock_context = MagicMock()
mock_context.socket.return_value = mock_req_socket
monkeypatch.setattr(robot.Context, "instance", lambda: mock_context)
# Replace logger methods to avoid noisy logs in tests
monkeypatch.setattr(robot.logger, "debug", MagicMock())
monkeypatch.setattr(robot.logger, "error", MagicMock())
# Act
response = client.get("/commands/gesture/tags")
response = client.get("/commands/gesture/single")
# Assert
assert response.status_code == 200
assert response.json() == {"available_gesture_tags": ["wave", "nod", "point", "dance"]}
assert response.json() == {"available_gestures": ["wave", "point"]}
# Verify ZeroMQ REQ interactions
mock_req_socket.connect.assert_called_once_with("tcp://localhost:7788")
mock_req_socket.send.assert_awaited_once_with(b"None")
mock_req_socket.send_json.assert_awaited_once_with({"type": "single", "count": None})
mock_req_socket.recv.assert_awaited_once()
@pytest.mark.asyncio
async def test_get_available_gesture_tags_with_amount(client, monkeypatch):
"""
The endpoint currently ignores the 'amount' TODO, so behavior is the same as 'success'.
This test asserts that the endpoint still sends b"None" and returns the tags.
"""
# Arrange
async def test_get_available_single_gestures_timeout(client, monkeypatch):
mock_req_socket = AsyncMock(spec=zmq.asyncio.Socket)
mock_req_socket.connect = MagicMock()
mock_req_socket.send = AsyncMock()
response_data = {"tags": ["wave", "nod"]}
mock_req_socket.recv = AsyncMock(return_value=json.dumps(response_data).encode())
mock_context = MagicMock()
mock_context.socket.return_value = mock_req_socket
monkeypatch.setattr(robot.Context, "instance", lambda: mock_context)
monkeypatch.setattr(robot.logger, "debug", MagicMock())
monkeypatch.setattr(robot.logger, "error", MagicMock())
# Act
response = client.get("/commands/gesture/tags")
# Assert
assert response.status_code == 200
assert response.json() == {"available_gesture_tags": ["wave", "nod"]}
mock_req_socket.connect.assert_called_once_with("tcp://localhost:7788")
mock_req_socket.send.assert_awaited_once_with(b"None")
@pytest.mark.asyncio
async def test_get_available_gesture_tags_timeout(client, monkeypatch):
"""
Test timeout scenario when fetching gesture tags. Endpoint should handle TimeoutError
and return an empty list while logging the timeout.
"""
# Arrange
mock_req_socket = AsyncMock(spec=zmq.asyncio.Socket)
mock_req_socket.connect = MagicMock()
mock_req_socket.send = AsyncMock()
mock_req_socket.send_json = AsyncMock()
mock_req_socket.recv = AsyncMock(side_effect=TimeoutError)
mock_context = MagicMock()
mock_context.socket.return_value = mock_req_socket
monkeypatch.setattr(robot.Context, "instance", lambda: mock_context)
# Patch logger.debug so we can assert it was called with the expected message
mock_debug = MagicMock()
monkeypatch.setattr(robot.logger, "debug", mock_debug)
monkeypatch.setattr(robot.logger, "error", MagicMock())
response = client.get("/commands/gesture/single")
# Act
response = client.get("/commands/gesture/tags")
# Assert
assert response.status_code == 200
assert response.json() == {"available_gesture_tags": []}
# Verify the timeout was logged using the exact string from the endpoint code
mock_debug.assert_called_once_with("Got timeout error fetching gestures.")
mock_req_socket.connect.assert_called_once_with("tcp://localhost:7788")
mock_req_socket.send.assert_awaited_once_with(b"None")
mock_req_socket.recv.assert_awaited_once()
assert response.json() == {"available_gestures": []}
@pytest.mark.asyncio
async def test_get_available_gesture_tags_empty_response(client, monkeypatch):
async def test_get_available_single_gestures_missing_key(client, monkeypatch):
"""
Test scenario when response contains an empty 'tags' list.
Test response missing 'single_gestures' key.
"""
# Arrange
mock_req_socket = AsyncMock(spec=zmq.asyncio.Socket)
mock_req_socket.connect = MagicMock()
mock_req_socket.send = AsyncMock()
response_data = {"tags": []}
mock_req_socket.recv = AsyncMock(return_value=json.dumps(response_data).encode())
mock_req_socket.send_json = AsyncMock()
mock_req_socket.recv = AsyncMock(return_value=json.dumps({"unexpected": "value"}).encode())
mock_context = MagicMock()
mock_context.socket.return_value = mock_req_socket
@@ -351,52 +291,21 @@ async def test_get_available_gesture_tags_empty_response(client, monkeypatch):
monkeypatch.setattr(robot.logger, "debug", MagicMock())
monkeypatch.setattr(robot.logger, "error", MagicMock())
# Act
response = client.get("/commands/gesture/tags")
response = client.get("/commands/gesture/single")
# Assert
assert response.status_code == 200
assert response.json() == {"available_gesture_tags": []}
assert response.json() == {"available_gestures": []}
@pytest.mark.asyncio
async def test_get_available_gesture_tags_missing_tags_key(client, monkeypatch):
async def test_get_available_single_gestures_invalid_json(client, monkeypatch):
"""
Test scenario when response JSON doesn't contain 'tags' key.
Test invalid JSON response for single gestures.
"""
# Arrange
mock_req_socket = AsyncMock(spec=zmq.asyncio.Socket)
mock_req_socket.connect = MagicMock()
mock_req_socket.send = AsyncMock()
response_data = {"some_other_key": "value"}
mock_req_socket.recv = AsyncMock(return_value=json.dumps(response_data).encode())
mock_context = MagicMock()
mock_context.socket.return_value = mock_req_socket
monkeypatch.setattr(robot.Context, "instance", lambda: mock_context)
monkeypatch.setattr(robot.logger, "debug", MagicMock())
monkeypatch.setattr(robot.logger, "error", MagicMock())
# Act
response = client.get("/commands/gesture/tags")
# Assert
assert response.status_code == 200
assert response.json() == {"available_gesture_tags": []}
@pytest.mark.asyncio
async def test_get_available_gesture_tags_invalid_json(client, monkeypatch):
"""
Test scenario when response contains invalid JSON. Endpoint should log the error
and return an empty list.
"""
# Arrange
mock_req_socket = AsyncMock(spec=zmq.asyncio.Socket)
mock_req_socket.connect = MagicMock()
mock_req_socket.send = AsyncMock()
mock_req_socket.recv = AsyncMock(return_value=b"invalid json")
mock_req_socket.send_json = AsyncMock()
mock_req_socket.recv = AsyncMock(return_value=b"not-json")
mock_context = MagicMock()
mock_context.socket.return_value = mock_req_socket
@@ -406,10 +315,78 @@ async def test_get_available_gesture_tags_invalid_json(client, monkeypatch):
monkeypatch.setattr(robot.logger, "error", mock_error)
monkeypatch.setattr(robot.logger, "debug", MagicMock())
# Act
response = client.get("/commands/gesture/tags")
response = client.get("/commands/gesture/single")
# Assert - invalid JSON should lead to empty list and error log invocation
assert response.status_code == 200
assert response.json() == {"available_gesture_tags": []}
assert response.json() == {"available_gestures": []}
assert mock_error.call_count == 1
@pytest.mark.asyncio
async def test_get_available_basic_gestures_success(client, monkeypatch):
"""
Test successful retrieval of basic gestures.
"""
mock_req_socket = AsyncMock(spec=zmq.asyncio.Socket)
mock_req_socket.connect = MagicMock()
mock_req_socket.send_json = AsyncMock()
response_data = {"basic_gestures": ["nod", "shake"]}
mock_req_socket.recv = AsyncMock(return_value=json.dumps(response_data).encode())
mock_context = MagicMock()
mock_context.socket.return_value = mock_req_socket
monkeypatch.setattr(robot.Context, "instance", lambda: mock_context)
monkeypatch.setattr(robot.logger, "debug", MagicMock())
monkeypatch.setattr(robot.logger, "error", MagicMock())
response = client.get("/commands/gesture/basic")
assert response.status_code == 200
assert response.json() == {"available_gestures": ["nod", "shake"]}
mock_req_socket.connect.assert_called_once_with("tcp://localhost:7788")
mock_req_socket.send_json.assert_awaited_once_with({"type": "basic", "count": None})
mock_req_socket.recv.assert_awaited_once()
@pytest.mark.asyncio
async def test_get_available_basic_gestures_timeout(client, monkeypatch):
mock_req_socket = AsyncMock(spec=zmq.asyncio.Socket)
mock_req_socket.connect = MagicMock()
mock_req_socket.send_json = AsyncMock()
mock_req_socket.recv = AsyncMock(side_effect=TimeoutError)
mock_context = MagicMock()
mock_context.socket.return_value = mock_req_socket
monkeypatch.setattr(robot.Context, "instance", lambda: mock_context)
response = client.get("/commands/gesture/basic")
assert response.status_code == 200
assert response.json() == {"available_gestures": []}
@pytest.mark.asyncio
async def test_get_available_basic_gestures_invalid_json(client, monkeypatch):
"""
Test invalid JSON response for basic gestures.
"""
mock_req_socket = AsyncMock(spec=zmq.asyncio.Socket)
mock_req_socket.connect = MagicMock()
mock_req_socket.send_json = AsyncMock()
mock_req_socket.recv = AsyncMock(return_value=b"{invalid json")
mock_context = MagicMock()
mock_context.socket.return_value = mock_req_socket
monkeypatch.setattr(robot.Context, "instance", lambda: mock_context)
mock_error = MagicMock()
monkeypatch.setattr(robot.logger, "error", mock_error)
monkeypatch.setattr(robot.logger, "debug", MagicMock())
response = client.get("/commands/gesture/basic")
assert response.status_code == 200
assert response.json() == {"available_gestures": []}
assert mock_error.call_count == 1