diff --git a/src/control_backend/agents/ri_communication_agent.py b/src/control_backend/agents/ri_communication_agent.py index 2033857..8889d7c 100644 --- a/src/control_backend/agents/ri_communication_agent.py +++ b/src/control_backend/agents/ri_communication_agent.py @@ -17,7 +17,9 @@ class RICommunicationAgent(Agent): _address = "" _bind = True - def __init__(self, jid: str, password: str, port: int = 5222, verify_security: bool = False, address = "tcp://localhost:0000", bind = False): + def __init__(self, jid: str, password: str, port: int = 5222, + verify_security: bool = False, address = "tcp://localhost:0000", + bind = False): super().__init__(jid, password, port, verify_security) self._address = address self._bind = bind @@ -54,7 +56,8 @@ class RICommunicationAgent(Agent): case "ping": await asyncio.sleep(1) case _: - logger.info("Received message with topic different than ping, while ping expected.") + logger.info("Received message with topic different than ping," \ + " while ping expected.") async def setup(self, max_retries: int = 5): @@ -82,7 +85,8 @@ class RICommunicationAgent(Agent): received_message = await asyncio.wait_for(self.req_socket.recv_json(), timeout=20.0) except asyncio.TimeoutError: - logger.warning("No connection established in 20 seconds (attempt %d/%d)", retries + 1, max_retries) + logger.warning("No connection established in 20 seconds (attempt %d/%d)", + retries + 1, max_retries) retries += 1 continue @@ -95,7 +99,8 @@ class RICommunicationAgent(Agent): endpoint = received_message.get("endpoint") if endpoint != "negotiate/ports": # TODO: Should this send a message back? - logger.error("Invalid endpoint '%s' received (attempt %d/%d)", endpoint, retries + 1, max_retries) + logger.error("Invalid endpoint '%s' received (attempt %d/%d)", + endpoint, retries + 1, max_retries) retries += 1 continue @@ -120,7 +125,8 @@ class RICommunicationAgent(Agent): self.req_socket.bind(addr) case "actuation": ri_commands_agent = RICommandAgent( - settings.agent_settings.ri_command_agent_name + '@' + settings.agent_settings.host, + settings.agent_settings.ri_command_agent_name + + '@' + settings.agent_settings.host, settings.agent_settings.ri_command_agent_name, address=addr, bind=bind ) diff --git a/src/control_backend/main.py b/src/control_backend/main.py index 2e772a6..c475846 100644 --- a/src/control_backend/main.py +++ b/src/control_backend/main.py @@ -33,12 +33,16 @@ async def lifespan(app: FastAPI): logger.info("Internal publishing socket bound to %s", internal_comm_socket) # Initiate agents - ri_communication_agent = RICommunicationAgent(settings.agent_settings.ri_communication_agent_name + '@' + settings.agent_settings.host, + ri_communication_agent = RICommunicationAgent(settings.agent_settings.ri_communication_agent_name + + '@' + settings.agent_settings.host, settings.agent_settings.ri_communication_agent_name, address="tcp://*:5555", bind=True) await ri_communication_agent.start() - bdi_core = BDICoreAgent(settings.agent_settings.bdi_core_agent_name + '@' + settings.agent_settings.host, settings.agent_settings.bdi_core_agent_name, "src/control_backend/agents/bdi/rules.asl") + bdi_core = BDICoreAgent(settings.agent_settings.bdi_core_agent_name + + '@' + settings.agent_settings.host, + settings.agent_settings.bdi_core_agent_name, + "src/control_backend/agents/bdi/rules.asl") await bdi_core.start() yield diff --git a/test/integration/agents/test_ri_commands_agent.py b/test/integration/agents/test_ri_commands_agent.py index 4ed8dc1..a21af3c 100644 --- a/test/integration/agents/test_ri_commands_agent.py +++ b/test/integration/agents/test_ri_commands_agent.py @@ -10,10 +10,12 @@ from control_backend.schemas.ri_message import SpeechCommand async def test_setup_bind(monkeypatch): """Test setup with bind=True""" fake_socket = MagicMock() - monkeypatch.setattr("control_backend.agents.ri_command_agent.context.socket", lambda _: fake_socket) + monkeypatch.setattr("control_backend.agents.ri_command_agent.context.socket", + lambda _: fake_socket) agent = RICommandAgent("test@server", "password", address="tcp://localhost:5555", bind=True) - monkeypatch.setattr("control_backend.agents.ri_command_agent.settings", MagicMock(zmq_settings=MagicMock(internal_comm_address="tcp://internal:1234"))) + monkeypatch.setattr("control_backend.agents.ri_command_agent.settings", + MagicMock(zmq_settings=MagicMock(internal_comm_address="tcp://internal:1234"))) await agent.setup() @@ -30,10 +32,12 @@ async def test_setup_bind(monkeypatch): async def test_setup_connect(monkeypatch): """Test setup with bind=False""" fake_socket = MagicMock() - monkeypatch.setattr("control_backend.agents.ri_command_agent.context.socket", lambda _: fake_socket) + monkeypatch.setattr("control_backend.agents.ri_command_agent.context.socket", + lambda _: fake_socket) agent = RICommandAgent("test@server", "password", address="tcp://localhost:5555", bind=False) - monkeypatch.setattr("control_backend.agents.ri_command_agent.settings", MagicMock(zmq_settings=MagicMock(internal_comm_address="tcp://internal:1234"))) + monkeypatch.setattr("control_backend.agents.ri_command_agent.settings", + MagicMock(zmq_settings=MagicMock(internal_comm_address="tcp://internal:1234"))) await agent.setup() @@ -45,7 +49,8 @@ async def test_send_commands_behaviour_valid_message(): """Test behaviour with valid JSON message""" fake_socket = AsyncMock() message_dict = {"message": "hello"} - fake_socket.recv_multipart = AsyncMock(return_value=(b"command", json.dumps(message_dict).encode("utf-8"))) + fake_socket.recv_multipart = AsyncMock(return_value=(b"command", + json.dumps(message_dict).encode("utf-8"))) fake_socket.send_json = AsyncMock() agent = RICommandAgent("test@server", "password") diff --git a/test/integration/agents/test_ri_communication_agent.py b/test/integration/agents/test_ri_communication_agent.py index 8228608..d778640 100644 --- a/test/integration/agents/test_ri_communication_agent.py +++ b/test/integration/agents/test_ri_communication_agent.py @@ -69,15 +69,18 @@ async def test_setup_creates_socket_and_negotiate_1(monkeypatch): fake_socket.recv_json = fake_json_correct_negototiate_1() # Mock context.socket to return our fake socket - monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", lambda _: fake_socket) + monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", + lambda _: fake_socket) # Mock RICommandAgent agent startup - with patch("control_backend.agents.ri_communication_agent.RICommandAgent", autospec=True) as MockCommandAgent: + with patch("control_backend.agents.ri_communication_agent.RICommandAgent", + autospec=True) as MockCommandAgent: fake_agent_instance = MockCommandAgent.return_value fake_agent_instance.start = AsyncMock() # --- Act --- - agent = RICommunicationAgent("test@server", "password", address="tcp://localhost:5555", bind=False) + agent = RICommunicationAgent("test@server", "password", + address="tcp://localhost:5555", bind=False) await agent.setup() # --- Assert --- @@ -105,15 +108,18 @@ async def test_setup_creates_socket_and_negotiate_2(monkeypatch): fake_socket.recv_json = fake_json_correct_negototiate_2() # Mock context.socket to return our fake socket - monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", lambda _: fake_socket) + monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", + lambda _: fake_socket) # Mock RICommandAgent agent startup - with patch("control_backend.agents.ri_communication_agent.RICommandAgent", autospec=True) as MockCommandAgent: + with patch("control_backend.agents.ri_communication_agent.RICommandAgent", + autospec=True) as MockCommandAgent: fake_agent_instance = MockCommandAgent.return_value fake_agent_instance.start = AsyncMock() # --- Act --- - agent = RICommunicationAgent("test@server", "password", address="tcp://localhost:5555", bind=False) + agent = RICommunicationAgent("test@server", "password", + address="tcp://localhost:5555", bind=False) await agent.setup() # --- Assert --- @@ -141,20 +147,23 @@ async def test_setup_creates_socket_and_negotiate_3(monkeypatch, caplog): fake_socket.recv_json = fake_json_wrong_negototiate_1() # Mock context.socket to return our fake socket - monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", lambda _: fake_socket) + monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", + lambda _: fake_socket) # Mock RICommandAgent agent startup # We are sending wrong negotiation info to the communication agent, so we should retry and expect a # better response, within a limited time. - with patch("control_backend.agents.ri_communication_agent.RICommandAgent", autospec=True) as MockCommandAgent: + with patch("control_backend.agents.ri_communication_agent.RICommandAgent", + autospec=True) as MockCommandAgent: fake_agent_instance = MockCommandAgent.return_value fake_agent_instance.start = AsyncMock() # --- Act --- with caplog.at_level("ERROR"): - agent = RICommunicationAgent("test@server", "password", address="tcp://localhost:5555", bind=False) + agent = RICommunicationAgent("test@server", "password", + address="tcp://localhost:5555", bind=False) await agent.setup(max_retries=1) # --- Assert --- @@ -179,15 +188,18 @@ async def test_setup_creates_socket_and_negotiate_4(monkeypatch): fake_socket.recv_json = fake_json_correct_negototiate_3() # Mock context.socket to return our fake socket - monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", lambda _: fake_socket) + monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", + lambda _: fake_socket) # Mock RICommandAgent agent startup - with patch("control_backend.agents.ri_communication_agent.RICommandAgent", autospec=True) as MockCommandAgent: + with patch("control_backend.agents.ri_communication_agent.RICommandAgent", + autospec=True) as MockCommandAgent: fake_agent_instance = MockCommandAgent.return_value fake_agent_instance.start = AsyncMock() # --- Act --- - agent = RICommunicationAgent("test@server", "password", address="tcp://localhost:5555", bind=True) + agent = RICommunicationAgent("test@server", "password", + address="tcp://localhost:5555", bind=True) await agent.setup() # --- Assert --- @@ -215,15 +227,18 @@ async def test_setup_creates_socket_and_negotiate_5(monkeypatch): fake_socket.recv_json = fake_json_correct_negototiate_4() # Mock context.socket to return our fake socket - monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", lambda _: fake_socket) + monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", + lambda _: fake_socket) # Mock RICommandAgent agent startup - with patch("control_backend.agents.ri_communication_agent.RICommandAgent", autospec=True) as MockCommandAgent: + with patch("control_backend.agents.ri_communication_agent.RICommandAgent", + autospec=True) as MockCommandAgent: fake_agent_instance = MockCommandAgent.return_value fake_agent_instance.start = AsyncMock() # --- Act --- - agent = RICommunicationAgent("test@server", "password", address="tcp://localhost:5555", bind=False) + agent = RICommunicationAgent("test@server", "password", + address="tcp://localhost:5555", bind=False) await agent.setup() # --- Assert --- @@ -251,15 +266,18 @@ async def test_setup_creates_socket_and_negotiate_6(monkeypatch): fake_socket.recv_json = fake_json_correct_negototiate_5() # Mock context.socket to return our fake socket - monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", lambda _: fake_socket) + monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", + lambda _: fake_socket) # Mock RICommandAgent agent startup - with patch("control_backend.agents.ri_communication_agent.RICommandAgent", autospec=True) as MockCommandAgent: + with patch("control_backend.agents.ri_communication_agent.RICommandAgent", + autospec=True) as MockCommandAgent: fake_agent_instance = MockCommandAgent.return_value fake_agent_instance.start = AsyncMock() # --- Act --- - agent = RICommunicationAgent("test@server", "password", address="tcp://localhost:5555", bind=False) + agent = RICommunicationAgent("test@server", "password", + address="tcp://localhost:5555", bind=False) await agent.setup() # --- Assert --- @@ -287,20 +305,23 @@ async def test_setup_creates_socket_and_negotiate_7(monkeypatch, caplog): fake_socket.recv_json = fake_json_invalid_id_negototiate() # Mock context.socket to return our fake socket - monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", lambda _: fake_socket) + monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", + lambda _: fake_socket) # Mock RICommandAgent agent startup # We are sending wrong negotiation info to the communication agent, so we should retry and expect a # better response, within a limited time. - with patch("control_backend.agents.ri_communication_agent.RICommandAgent", autospec=True) as MockCommandAgent: + with patch("control_backend.agents.ri_communication_agent.RICommandAgent", + autospec=True) as MockCommandAgent: fake_agent_instance = MockCommandAgent.return_value fake_agent_instance.start = AsyncMock() # --- Act --- with caplog.at_level("WARNING"): - agent = RICommunicationAgent("test@server", "password", address="tcp://localhost:5555", bind=False) + agent = RICommunicationAgent("test@server", "password", + address="tcp://localhost:5555", bind=False) await agent.setup(max_retries=1) # --- Assert --- @@ -323,15 +344,18 @@ async def test_setup_creates_socket_and_negotiate_timeout(monkeypatch, caplog): fake_socket.recv_json = AsyncMock(side_effect=asyncio.TimeoutError) # Mock context.socket to return our fake socket - monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", lambda _: fake_socket) + monkeypatch.setattr("control_backend.agents.ri_communication_agent.context.socket", + lambda _: fake_socket) - with patch("control_backend.agents.ri_communication_agent.RICommandAgent", autospec=True) as MockCommandAgent: + with patch("control_backend.agents.ri_communication_agent.RICommandAgent", + autospec=True) as MockCommandAgent: fake_agent_instance = MockCommandAgent.return_value fake_agent_instance.start = AsyncMock() # --- Act --- with caplog.at_level("WARNING"): - agent = RICommunicationAgent("test@server", "password", address="tcp://localhost:5555", bind=False) + agent = RICommunicationAgent("test@server", "password", + address="tcp://localhost:5555", bind=False) await agent.setup(max_retries=1) # --- Assert --- @@ -453,7 +477,8 @@ async def test_setup_unexpected_exception(monkeypatch, caplog): lambda _: fake_socket ) - agent = RICommunicationAgent("test@server", "password", address="tcp://localhost:5555", bind=False) + agent = RICommunicationAgent("test@server", "password", + address="tcp://localhost:5555", bind=False) with caplog.at_level("ERROR"): await agent.setup(max_retries=1) @@ -468,7 +493,8 @@ async def test_setup_unpacking_exception(monkeypatch, caplog): fake_socket.send_json = AsyncMock() # Make recv_json return malformed negotiation data to trigger unpacking exception - malformed_data = {"endpoint": "negotiate/ports", "data": [ {"id": "main"} ]} # missing 'port' and 'bind' + malformed_data = {"endpoint": "negotiate/ports", + "data": [ {"id": "main"} ]} # missing 'port' and 'bind' fake_socket.recv_json = AsyncMock(return_value=malformed_data) # Patch context.socket @@ -478,11 +504,13 @@ async def test_setup_unpacking_exception(monkeypatch, caplog): ) # Patch RICommandAgent so it won't actually start - with patch("control_backend.agents.ri_communication_agent.RICommandAgent", autospec=True) as MockCommandAgent: + with patch("control_backend.agents.ri_communication_agent.RICommandAgent", + autospec=True) as MockCommandAgent: fake_agent_instance = MockCommandAgent.return_value fake_agent_instance.start = AsyncMock() - agent = RICommunicationAgent("test@server", "password", address="tcp://localhost:5555", bind=False) + agent = RICommunicationAgent("test@server", "password", + address="tcp://localhost:5555", bind=False) # --- Act & Assert --- with caplog.at_level("ERROR"):