Gestures in the CB. #36
@@ -89,7 +89,7 @@ async def get_available_gesture_tags(request: Request, count=0):
|
|||||||
:return: A list of available gesture tags.
|
:return: A list of available gesture tags.
|
||||||
"""
|
"""
|
||||||
req_socket = Context.instance().socket(zmq.REQ)
|
req_socket = Context.instance().socket(zmq.REQ)
|
||||||
req_socket.connect(request.app.state.gesture_rep_address)
|
req_socket.connect(settings.zmq_settings.internal_gesture_rep_adress)
|
||||||
|
|
||||||
# Check to see if we've got any count given in the query parameter
|
# Check to see if we've got any count given in the query parameter
|
||||||
amount = count or None
|
amount = count or None
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ async def test_setup_bind(zmq_context, mocker):
|
|||||||
# Check PUB socket binding
|
# Check PUB socket binding
|
||||||
fake_socket.bind.assert_any_call("tcp://localhost:5556")
|
fake_socket.bind.assert_any_call("tcp://localhost:5556")
|
||||||
# Check REP socket binding
|
# Check REP socket binding
|
||||||
fake_socket.bind.assert_any_call("tcp://localhost:7788")
|
fake_socket.bind.assert_called()
|
||||||
|
|
||||||
# Check SUB socket connection and subscriptions
|
# Check SUB socket connection and subscriptions
|
||||||
fake_socket.connect.assert_any_call("tcp://internal:1234")
|
fake_socket.connect.assert_any_call("tcp://internal:1234")
|
||||||
@@ -63,7 +63,7 @@ async def test_setup_connect(zmq_context, mocker):
|
|||||||
fake_socket.connect.assert_any_call("tcp://localhost:5556")
|
fake_socket.connect.assert_any_call("tcp://localhost:5556")
|
||||||
fake_socket.connect.assert_any_call("tcp://internal:1234")
|
fake_socket.connect.assert_any_call("tcp://internal:1234")
|
||||||
# Check REP socket binding (always binds)
|
# Check REP socket binding (always binds)
|
||||||
fake_socket.bind.assert_any_call("tcp://localhost:7788")
|
fake_socket.bind.assert_called()
|
||||||
|
|
||||||
# Check behavior was added (twice)
|
# Check behavior was added (twice)
|
||||||
assert agent.add_behavior.call_count == 2
|
assert agent.add_behavior.call_count == 2
|
||||||
|
|||||||
@@ -8,6 +8,11 @@ from control_backend.agents.actuation.robot_speech_agent import RobotSpeechAgent
|
|||||||
from control_backend.core.agent_system import InternalMessage
|
from control_backend.core.agent_system import InternalMessage
|
||||||
|
|
||||||
|
|
||||||
|
def mock_speech_agent():
|
||||||
|
agent = RobotSpeechAgent("robot_speech", address="tcp://localhost:5555", bind=False)
|
||||||
|
return agent
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def zmq_context(mocker):
|
def zmq_context(mocker):
|
||||||
mock_context = mocker.patch(
|
mock_context = mocker.patch(
|
||||||
@@ -56,7 +61,7 @@ async def test_setup_connect(zmq_context, mocker):
|
|||||||
async def test_handle_message_sends_command():
|
async def test_handle_message_sends_command():
|
||||||
"""Internal message is forwarded to robot pub socket as JSON."""
|
"""Internal message is forwarded to robot pub socket as JSON."""
|
||||||
pubsocket = AsyncMock()
|
pubsocket = AsyncMock()
|
||||||
agent = RobotSpeechAgent("robot_speech")
|
agent = mock_speech_agent()
|
||||||
agent.pubsocket = pubsocket
|
agent.pubsocket = pubsocket
|
||||||
|
|
||||||
payload = {"endpoint": "actuate/speech", "data": "hello"}
|
payload = {"endpoint": "actuate/speech", "data": "hello"}
|
||||||
@@ -80,7 +85,7 @@ async def test_zmq_command_loop_valid_payload(zmq_context):
|
|||||||
|
|
||||||
fake_socket.recv_multipart = recv_once
|
fake_socket.recv_multipart = recv_once
|
||||||
fake_socket.send_json = AsyncMock()
|
fake_socket.send_json = AsyncMock()
|
||||||
agent = RobotSpeechAgent("robot_speech")
|
agent = mock_speech_agent()
|
||||||
agent.subsocket = fake_socket
|
agent.subsocket = fake_socket
|
||||||
agent.pubsocket = fake_socket
|
agent.pubsocket = fake_socket
|
||||||
agent._running = True
|
agent._running = True
|
||||||
@@ -101,7 +106,7 @@ async def test_zmq_command_loop_invalid_json():
|
|||||||
|
|
||||||
fake_socket.recv_multipart = recv_once
|
fake_socket.recv_multipart = recv_once
|
||||||
fake_socket.send_json = AsyncMock()
|
fake_socket.send_json = AsyncMock()
|
||||||
agent = RobotSpeechAgent("robot_speech")
|
agent = mock_speech_agent()
|
||||||
agent.subsocket = fake_socket
|
agent.subsocket = fake_socket
|
||||||
agent.pubsocket = fake_socket
|
agent.pubsocket = fake_socket
|
||||||
agent._running = True
|
agent._running = True
|
||||||
@@ -115,7 +120,7 @@ async def test_zmq_command_loop_invalid_json():
|
|||||||
async def test_handle_message_invalid_payload():
|
async def test_handle_message_invalid_payload():
|
||||||
"""Invalid payload is caught and does not send."""
|
"""Invalid payload is caught and does not send."""
|
||||||
pubsocket = AsyncMock()
|
pubsocket = AsyncMock()
|
||||||
agent = RobotSpeechAgent("robot_speech")
|
agent = mock_speech_agent()
|
||||||
agent.pubsocket = pubsocket
|
agent.pubsocket = pubsocket
|
||||||
|
|
||||||
msg = InternalMessage(to="robot", sender="tester", body=json.dumps({"bad": "data"}))
|
msg = InternalMessage(to="robot", sender="tester", body=json.dumps({"bad": "data"}))
|
||||||
@@ -129,7 +134,7 @@ async def test_handle_message_invalid_payload():
|
|||||||
async def test_stop_closes_sockets():
|
async def test_stop_closes_sockets():
|
||||||
pubsocket = MagicMock()
|
pubsocket = MagicMock()
|
||||||
subsocket = MagicMock()
|
subsocket = MagicMock()
|
||||||
agent = RobotSpeechAgent("robot_speech")
|
agent = mock_speech_agent()
|
||||||
agent.pubsocket = pubsocket
|
agent.pubsocket = pubsocket
|
||||||
agent.subsocket = subsocket
|
agent.subsocket = subsocket
|
||||||
|
|
||||||
|
|||||||
@@ -62,11 +62,11 @@ def test_receive_speech_command_success(client):
|
|||||||
speech_command = SpeechCommand(**command_data)
|
speech_command = SpeechCommand(**command_data)
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
response = client.post("/command", json=command_data)
|
response = client.post("/command/speech", json=command_data)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert response.status_code == 202
|
assert response.status_code == 202
|
||||||
assert response.json() == {"status": "Command received"}
|
assert response.json() == {"status": "Speech command received"}
|
||||||
|
|
||||||
# Verify that the ZMQ socket was used correctly
|
# Verify that the ZMQ socket was used correctly
|
||||||
mock_pub_socket.send_multipart.assert_awaited_once_with(
|
mock_pub_socket.send_multipart.assert_awaited_once_with(
|
||||||
@@ -87,11 +87,11 @@ def test_receive_gesture_command_success(client):
|
|||||||
gesture_command = GestureCommand(**command_data)
|
gesture_command = GestureCommand(**command_data)
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
response = client.post("/command", json=command_data)
|
response = client.post("/command/gesture", json=command_data)
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert response.status_code == 202
|
assert response.status_code == 202
|
||||||
assert response.json() == {"status": "Command received"}
|
assert response.json() == {"status": "Gesture command received"}
|
||||||
|
|
||||||
# Verify that the ZMQ socket was used correctly
|
# Verify that the ZMQ socket was used correctly
|
||||||
mock_pub_socket.send_multipart.assert_awaited_once_with(
|
mock_pub_socket.send_multipart.assert_awaited_once_with(
|
||||||
@@ -99,13 +99,23 @@ def test_receive_gesture_command_success(client):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_receive_command_invalid_payload(client):
|
def test_receive_speech_command_invalid_payload(client):
|
||||||
"""
|
"""
|
||||||
Test invalid data handling (schema validation).
|
Test invalid data handling (schema validation).
|
||||||
"""
|
"""
|
||||||
# Missing required field(s)
|
# Missing required field(s)
|
||||||
bad_payload = {"invalid": "data"}
|
bad_payload = {"invalid": "data"}
|
||||||
response = client.post("/command", json=bad_payload)
|
response = client.post("/command/speech", json=bad_payload)
|
||||||
|
assert response.status_code == 422 # validation error
|
||||||
|
|
||||||
|
|
||||||
|
def test_receive_gesture_command_invalid_payload(client):
|
||||||
|
"""
|
||||||
|
Test invalid data handling (schema validation).
|
||||||
|
"""
|
||||||
|
# Missing required field(s)
|
||||||
|
bad_payload = {"invalid": "data"}
|
||||||
|
response = client.post("/command/gesture", json=bad_payload)
|
||||||
assert response.status_code == 422 # validation error
|
assert response.status_code == 422 # validation error
|
||||||
|
|
||||||
|
|
||||||
@@ -243,7 +253,7 @@ async def test_get_available_gesture_tags_success(client, monkeypatch):
|
|||||||
monkeypatch.setattr(robot.logger, "error", MagicMock())
|
monkeypatch.setattr(robot.logger, "error", MagicMock())
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
response = client.get("/get_available_gesture_tags")
|
response = client.get("/commands/gesture/tags")
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
@@ -276,7 +286,7 @@ async def test_get_available_gesture_tags_with_amount(client, monkeypatch):
|
|||||||
monkeypatch.setattr(robot.logger, "error", MagicMock())
|
monkeypatch.setattr(robot.logger, "error", MagicMock())
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
response = client.get("/get_available_gesture_tags")
|
response = client.get("/commands/gesture/tags")
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
@@ -308,7 +318,7 @@ async def test_get_available_gesture_tags_timeout(client, monkeypatch):
|
|||||||
monkeypatch.setattr(robot.logger, "error", MagicMock())
|
monkeypatch.setattr(robot.logger, "error", MagicMock())
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
response = client.get("/get_available_gesture_tags")
|
response = client.get("/commands/gesture/tags")
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
@@ -342,7 +352,7 @@ async def test_get_available_gesture_tags_empty_response(client, monkeypatch):
|
|||||||
monkeypatch.setattr(robot.logger, "error", MagicMock())
|
monkeypatch.setattr(robot.logger, "error", MagicMock())
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
response = client.get("/get_available_gesture_tags")
|
response = client.get("/commands/gesture/tags")
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
@@ -369,7 +379,7 @@ async def test_get_available_gesture_tags_missing_tags_key(client, monkeypatch):
|
|||||||
monkeypatch.setattr(robot.logger, "error", MagicMock())
|
monkeypatch.setattr(robot.logger, "error", MagicMock())
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
response = client.get("/get_available_gesture_tags")
|
response = client.get("/commands/gesture/tags")
|
||||||
|
|
||||||
# Assert
|
# Assert
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
@@ -397,7 +407,7 @@ async def test_get_available_gesture_tags_invalid_json(client, monkeypatch):
|
|||||||
monkeypatch.setattr(robot.logger, "debug", MagicMock())
|
monkeypatch.setattr(robot.logger, "debug", MagicMock())
|
||||||
|
|
||||||
# Act
|
# Act
|
||||||
response = client.get("/get_available_gesture_tags")
|
response = client.get("/commands/gesture/tags")
|
||||||
|
|
||||||
# Assert - invalid JSON should lead to empty list and error log invocation
|
# Assert - invalid JSON should lead to empty list and error log invocation
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
|
|||||||
Reference in New Issue
Block a user