diff --git a/packages/fetchai/connections/soef/connection.py b/packages/fetchai/connections/soef/connection.py index b8c9578f3f..622543e773 100644 --- a/packages/fetchai/connections/soef/connection.py +++ b/packages/fetchai/connections/soef/connection.py @@ -21,6 +21,7 @@ import asyncio import copy import logging +import urllib from asyncio import CancelledError from concurrent.futures._base import CancelledError as ConcurrentCancelledError from concurrent.futures.thread import ThreadPoolExecutor @@ -88,6 +89,7 @@ class ModelNames: personality_agent = "personality_agent" search_model = "search_model" ping = "ping" + generic_command = "generic_command" class SOEFException(Exception): @@ -484,6 +486,7 @@ async def register_service( # pylint: disable=unused-argument "personality_agent": self._set_personality_piece_handler, "set_service_key": self._set_service_key_handler, "ping": self._ping_handler, + "generic_command": self._generic_command_handler, } # type: Dict[str, Callable] data_model_name = service_description.data_model.name @@ -493,9 +496,14 @@ async def register_service( # pylint: disable=unused-argument ) handler = data_model_handlers[data_model_name] - await handler(service_description) + await handler(service_description, oef_message, oef_search_dialogue) - async def _ping_handler(self, service_description: Description) -> None: + async def _ping_handler( + self, + service_description: Description, + oef_message: OefSearchMessage, # pylint: disable=unused-argument + oef_search_dialogue: OefSearchDialogue, # pylint: disable=unused-argument + ) -> None: """ Perform ping command. @@ -506,6 +514,51 @@ async def _ping_handler(self, service_description: Description) -> None: self._check_data_model(service_description, ModelNames.ping) await self._ping_command() + async def _generic_command_handler( + self, + service_description: Description, + oef_message: OefSearchMessage, + oef_search_dialogue: OefSearchDialogue, + ) -> None: + """ + Perform ping command. + + :param service_description: Service description + + :return None + """ + if not self.in_queue: # pragma: no cover + """not connected.""" + return + + self._check_data_model(service_description, ModelNames.generic_command) + command = service_description.values.get("command", None) + params = service_description.values.get("parameters", {}) + + if params: + params = urllib.parse.parse_qs(params) + + content = await self._generic_oef_command(command, params) + + message = oef_search_dialogue.reply( + performative=OefSearchMessage.Performative.SUCCESS, + target_message=oef_message, + agents_info=AgentsInfo( + { + "response": {"content": content}, + "command": service_description.values, + } + ), + ) + envelope = Envelope( + to=message.to, + sender=message.sender, + protocol_id=message.protocol_id, + message=message, + context=oef_search_dialogue.envelope_context, + ) + await self.in_queue.put(envelope) + async def _ping_command(self) -> None: """Perform ping on registered agent.""" await self._generic_oef_command("ping", {}) @@ -528,7 +581,12 @@ async def _ping_periodic(self, period: float = 30 * 60) -> None: self.logger.exception("Error on periodic ping command!") await asyncio.sleep(period) - async def _set_service_key_handler(self, service_description: Description) -> None: + async def _set_service_key_handler( + self, + service_description: Description, + oef_message: OefSearchMessage, # pylint: disable=unused-argument + oef_search_dialogue: OefSearchDialogue, # pylint: disable=unused-argument + ) -> None: """ Set service key from service description. @@ -585,7 +643,10 @@ async def _set_service_key(self, key: str, value: Union[str, int, float]) -> Non await self._generic_oef_command("set_service_key", {"key": key, "value": value}) async def _remove_service_key_handler( - self, service_description: Description + self, + service_description: Description, + oef_message: OefSearchMessage, # pylint: disable=unused-argument + oef_search_dialogue: OefSearchDialogue, # pylint: disable=unused-argument ) -> None: """ Remove service key from service description. @@ -611,7 +672,10 @@ async def _remove_service_key(self, key: str) -> None: await self._generic_oef_command("remove_service_key", {"key": key}) async def _register_location_handler( - self, service_description: Description + self, + service_description: Description, + oef_message: OefSearchMessage, # pylint: disable=unused-argument + oef_search_dialogue: OefSearchDialogue, # pylint: disable=unused-argument ) -> None: """ Register service with location. @@ -686,7 +750,10 @@ async def _set_location( self.agent_location = agent_location async def _set_personality_piece_handler( - self, service_description: Description + self, + service_description: Description, + oef_message: OefSearchMessage, # pylint: disable=unused-argument + oef_search_dialogue: OefSearchDialogue, # pylint: disable=unused-argument ) -> None: """ Set the personality piece. @@ -826,9 +893,9 @@ async def unregister_service( # pylint: disable=unused-argument if data_model_name == "location_agent": await handler() else: - await handler(service_description) + await handler(service_description, oef_message, oef_search_dialogue) - async def _unregister_agent(self) -> None: + async def _unregister_agent(self) -> None: # pylint: disable=unused-argument """ Unnregister a service_name from the SOEF. diff --git a/packages/fetchai/connections/soef/connection.yaml b/packages/fetchai/connections/soef/connection.yaml index dfa230855f..f11cd94684 100644 --- a/packages/fetchai/connections/soef/connection.yaml +++ b/packages/fetchai/connections/soef/connection.yaml @@ -8,7 +8,7 @@ aea_version: '>=0.6.0, <0.7.0' fingerprint: README.md: QmWwjETX39APP9RD5oVPeeCiDnUoDvjAcoVe2FK2Jc6anM __init__.py: Qmd5VBGFJHXFe1H45XoUh5mMSYBwvLSViJuGFeMgbPdQts - connection.py: QmW6JjJsAybe2w4CrjahvLuV3n3nGUXMTzYPQ7LmTq35E6 + connection.py: QmfK5khjQuqewKVuqyedgmToQvRbh69oT8f5WcSvzvvjJL fingerprint_ignore_patterns: [] protocols: - fetchai/oef_search:0.6.0 diff --git a/packages/fetchai/protocols/oef_search/README.md b/packages/fetchai/protocols/oef_search/README.md index 1f5d3ad205..9ab8c67a1f 100644 --- a/packages/fetchai/protocols/oef_search/README.md +++ b/packages/fetchai/protocols/oef_search/README.md @@ -25,7 +25,8 @@ speech_acts: search_result: agents: pt:list[pt:str] agents_info: ct:AgentsInfo - success: {} + success: + agents_info: ct:AgentsInfo oef_error: oef_error_operation: ct:OefErrorOperation ... diff --git a/packages/fetchai/protocols/oef_search/message.py b/packages/fetchai/protocols/oef_search/message.py index a3daa5238d..51190e1eee 100644 --- a/packages/fetchai/protocols/oef_search/message.py +++ b/packages/fetchai/protocols/oef_search/message.py @@ -255,7 +255,13 @@ def _is_consistent(self) -> bool: ), ) elif self.performative == OefSearchMessage.Performative.SUCCESS: - expected_nb_of_contents = 0 + expected_nb_of_contents = 1 + enforce( + type(self.agents_info) == CustomAgentsInfo, + "Invalid type for content 'agents_info'. Expected 'AgentsInfo'. Found '{}'.".format( + type(self.agents_info) + ), + ) elif self.performative == OefSearchMessage.Performative.OEF_ERROR: expected_nb_of_contents = 1 enforce( diff --git a/packages/fetchai/protocols/oef_search/oef_search.proto b/packages/fetchai/protocols/oef_search/oef_search.proto index 85ba6778e9..48e716699c 100644 --- a/packages/fetchai/protocols/oef_search/oef_search.proto +++ b/packages/fetchai/protocols/oef_search/oef_search.proto @@ -52,7 +52,9 @@ message OefSearchMessage{ AgentsInfo agents_info = 2; } - message Success_Performative{} + message Success_Performative{ + AgentsInfo agents_info = 1; + } message Oef_Error_Performative{ OefErrorOperation oef_error_operation = 1; diff --git a/packages/fetchai/protocols/oef_search/oef_search_pb2.py b/packages/fetchai/protocols/oef_search/oef_search_pb2.py index 7f5e854f9a..2997410b86 100644 --- a/packages/fetchai/protocols/oef_search/oef_search_pb2.py +++ b/packages/fetchai/protocols/oef_search/oef_search_pb2.py @@ -17,7 +17,7 @@ package="fetch.aea.OefSearch", syntax="proto3", serialized_options=None, - serialized_pb=b'\n\x10oef_search.proto\x12\x13\x66\x65tch.aea.OefSearch"\x98\r\n\x10OefSearchMessage\x12\x12\n\nmessage_id\x18\x01 \x01(\x05\x12"\n\x1a\x64ialogue_starter_reference\x18\x02 \x01(\t\x12$\n\x1c\x64ialogue_responder_reference\x18\x03 \x01(\t\x12\x0e\n\x06target\x18\x04 \x01(\x05\x12Q\n\toef_error\x18\x05 \x01(\x0b\x32<.fetch.aea.OefSearch.OefSearchMessage.Oef_Error_PerformativeH\x00\x12_\n\x10register_service\x18\x06 \x01(\x0b\x32\x43.fetch.aea.OefSearch.OefSearchMessage.Register_Service_PerformativeH\x00\x12Y\n\rsearch_result\x18\x07 \x01(\x0b\x32@.fetch.aea.OefSearch.OefSearchMessage.Search_Result_PerformativeH\x00\x12]\n\x0fsearch_services\x18\x08 \x01(\x0b\x32\x42.fetch.aea.OefSearch.OefSearchMessage.Search_Services_PerformativeH\x00\x12M\n\x07success\x18\t \x01(\x0b\x32:.fetch.aea.OefSearch.OefSearchMessage.Success_PerformativeH\x00\x12\x63\n\x12unregister_service\x18\n \x01(\x0b\x32\x45.fetch.aea.OefSearch.OefSearchMessage.Unregister_Service_PerformativeH\x00\x1a!\n\nAgentsInfo\x12\x13\n\x0b\x61gents_info\x18\x01 \x01(\x0c\x1a"\n\x0b\x44\x65scription\x12\x13\n\x0b\x64\x65scription\x18\x01 \x01(\x0c\x1a\xd1\x01\n\x11OefErrorOperation\x12W\n\toef_error\x18\x01 \x01(\x0e\x32\x44.fetch.aea.OefSearch.OefSearchMessage.OefErrorOperation.OefErrorEnum"c\n\x0cOefErrorEnum\x12\x14\n\x10REGISTER_SERVICE\x10\x00\x12\x16\n\x12UNREGISTER_SERVICE\x10\x01\x12\x13\n\x0fSEARCH_SERVICES\x10\x02\x12\x10\n\x0cSEND_MESSAGE\x10\x03\x1a\x8b\x01\n\x05Query\x12\x0f\n\x05\x62ytes\x18\x01 \x01(\x0cH\x00\x12\x46\n\x07nothing\x18\x02 \x01(\x0b\x32\x33.fetch.aea.OefSearch.OefSearchMessage.Query.NothingH\x00\x12\x15\n\x0bquery_bytes\x18\x03 \x01(\x0cH\x00\x1a\t\n\x07NothingB\x07\n\x05query\x1ao\n\x1dRegister_Service_Performative\x12N\n\x13service_description\x18\x01 \x01(\x0b\x32\x31.fetch.aea.OefSearch.OefSearchMessage.Description\x1aq\n\x1fUnregister_Service_Performative\x12N\n\x13service_description\x18\x01 \x01(\x0b\x32\x31.fetch.aea.OefSearch.OefSearchMessage.Description\x1aZ\n\x1cSearch_Services_Performative\x12:\n\x05query\x18\x01 \x01(\x0b\x32+.fetch.aea.OefSearch.OefSearchMessage.Query\x1as\n\x1aSearch_Result_Performative\x12\x0e\n\x06\x61gents\x18\x01 \x03(\t\x12\x45\n\x0b\x61gents_info\x18\x02 \x01(\x0b\x32\x30.fetch.aea.OefSearch.OefSearchMessage.AgentsInfo\x1a\x16\n\x14Success_Performative\x1an\n\x16Oef_Error_Performative\x12T\n\x13oef_error_operation\x18\x01 \x01(\x0b\x32\x37.fetch.aea.OefSearch.OefSearchMessage.OefErrorOperationB\x0e\n\x0cperformativeb\x06proto3', + serialized_pb=b'\n\x10oef_search.proto\x12\x13\x66\x65tch.aea.OefSearch"\xdf\r\n\x10OefSearchMessage\x12\x12\n\nmessage_id\x18\x01 \x01(\x05\x12"\n\x1a\x64ialogue_starter_reference\x18\x02 \x01(\t\x12$\n\x1c\x64ialogue_responder_reference\x18\x03 \x01(\t\x12\x0e\n\x06target\x18\x04 \x01(\x05\x12Q\n\toef_error\x18\x05 \x01(\x0b\x32<.fetch.aea.OefSearch.OefSearchMessage.Oef_Error_PerformativeH\x00\x12_\n\x10register_service\x18\x06 \x01(\x0b\x32\x43.fetch.aea.OefSearch.OefSearchMessage.Register_Service_PerformativeH\x00\x12Y\n\rsearch_result\x18\x07 \x01(\x0b\x32@.fetch.aea.OefSearch.OefSearchMessage.Search_Result_PerformativeH\x00\x12]\n\x0fsearch_services\x18\x08 \x01(\x0b\x32\x42.fetch.aea.OefSearch.OefSearchMessage.Search_Services_PerformativeH\x00\x12M\n\x07success\x18\t \x01(\x0b\x32:.fetch.aea.OefSearch.OefSearchMessage.Success_PerformativeH\x00\x12\x63\n\x12unregister_service\x18\n \x01(\x0b\x32\x45.fetch.aea.OefSearch.OefSearchMessage.Unregister_Service_PerformativeH\x00\x1a!\n\nAgentsInfo\x12\x13\n\x0b\x61gents_info\x18\x01 \x01(\x0c\x1a"\n\x0b\x44\x65scription\x12\x13\n\x0b\x64\x65scription\x18\x01 \x01(\x0c\x1a\xd1\x01\n\x11OefErrorOperation\x12W\n\toef_error\x18\x01 \x01(\x0e\x32\x44.fetch.aea.OefSearch.OefSearchMessage.OefErrorOperation.OefErrorEnum"c\n\x0cOefErrorEnum\x12\x14\n\x10REGISTER_SERVICE\x10\x00\x12\x16\n\x12UNREGISTER_SERVICE\x10\x01\x12\x13\n\x0fSEARCH_SERVICES\x10\x02\x12\x10\n\x0cSEND_MESSAGE\x10\x03\x1a\x8b\x01\n\x05Query\x12\x0f\n\x05\x62ytes\x18\x01 \x01(\x0cH\x00\x12\x46\n\x07nothing\x18\x02 \x01(\x0b\x32\x33.fetch.aea.OefSearch.OefSearchMessage.Query.NothingH\x00\x12\x15\n\x0bquery_bytes\x18\x03 \x01(\x0cH\x00\x1a\t\n\x07NothingB\x07\n\x05query\x1ao\n\x1dRegister_Service_Performative\x12N\n\x13service_description\x18\x01 \x01(\x0b\x32\x31.fetch.aea.OefSearch.OefSearchMessage.Description\x1aq\n\x1fUnregister_Service_Performative\x12N\n\x13service_description\x18\x01 \x01(\x0b\x32\x31.fetch.aea.OefSearch.OefSearchMessage.Description\x1aZ\n\x1cSearch_Services_Performative\x12:\n\x05query\x18\x01 \x01(\x0b\x32+.fetch.aea.OefSearch.OefSearchMessage.Query\x1as\n\x1aSearch_Result_Performative\x12\x0e\n\x06\x61gents\x18\x01 \x03(\t\x12\x45\n\x0b\x61gents_info\x18\x02 \x01(\x0b\x32\x30.fetch.aea.OefSearch.OefSearchMessage.AgentsInfo\x1a]\n\x14Success_Performative\x12\x45\n\x0b\x61gents_info\x18\x01 \x01(\x0b\x32\x30.fetch.aea.OefSearch.OefSearchMessage.AgentsInfo\x1an\n\x16Oef_Error_Performative\x12T\n\x13oef_error_operation\x18\x01 \x01(\x0b\x32\x37.fetch.aea.OefSearch.OefSearchMessage.OefErrorOperationB\x0e\n\x0cperformativeb\x06proto3', ) @@ -451,7 +451,26 @@ filename=None, file=DESCRIPTOR, containing_type=None, - fields=[], + fields=[ + _descriptor.FieldDescriptor( + name="agents_info", + full_name="fetch.aea.OefSearch.OefSearchMessage.Success_Performative.agents_info", + index=0, + number=1, + type=11, + cpp_type=10, + label=1, + has_default_value=False, + default_value=None, + message_type=None, + enum_type=None, + containing_type=None, + is_extension=False, + extension_scope=None, + serialized_options=None, + file=DESCRIPTOR, + ), + ], extensions=[], nested_types=[], enum_types=[], @@ -461,7 +480,7 @@ extension_ranges=[], oneofs=[], serialized_start=1580, - serialized_end=1602, + serialized_end=1673, ) _OEFSEARCHMESSAGE_OEF_ERROR_PERFORMATIVE = _descriptor.Descriptor( @@ -498,8 +517,8 @@ syntax="proto3", extension_ranges=[], oneofs=[], - serialized_start=1604, - serialized_end=1714, + serialized_start=1675, + serialized_end=1785, ) _OEFSEARCHMESSAGE = _descriptor.Descriptor( @@ -718,7 +737,7 @@ ), ], serialized_start=42, - serialized_end=1730, + serialized_end=1801, ) _OEFSEARCHMESSAGE_AGENTSINFO.containing_type = _OEFSEARCHMESSAGE @@ -769,6 +788,9 @@ "agents_info" ].message_type = _OEFSEARCHMESSAGE_AGENTSINFO _OEFSEARCHMESSAGE_SEARCH_RESULT_PERFORMATIVE.containing_type = _OEFSEARCHMESSAGE +_OEFSEARCHMESSAGE_SUCCESS_PERFORMATIVE.fields_by_name[ + "agents_info" +].message_type = _OEFSEARCHMESSAGE_AGENTSINFO _OEFSEARCHMESSAGE_SUCCESS_PERFORMATIVE.containing_type = _OEFSEARCHMESSAGE _OEFSEARCHMESSAGE_OEF_ERROR_PERFORMATIVE.fields_by_name[ "oef_error_operation" diff --git a/packages/fetchai/protocols/oef_search/protocol.yaml b/packages/fetchai/protocols/oef_search/protocol.yaml index 98bda65f61..e03193f84d 100644 --- a/packages/fetchai/protocols/oef_search/protocol.yaml +++ b/packages/fetchai/protocols/oef_search/protocol.yaml @@ -6,14 +6,14 @@ description: A protocol for interacting with an OEF search service. license: Apache-2.0 aea_version: '>=0.6.0, <0.7.0' fingerprint: - README.md: QmfGEYrF54F6i5RTGgLgzfhMCMgYBY8Q1iHwb9UhE96MDi + README.md: QmaGSTqxvQFKccBnLovhBbfSH3C3Sorrj7kFyZqW9qptLa __init__.py: QmRvTtynKcd7shmzgf8aZdcA5witjNL5cL2a7WPgscp7wq custom_types.py: QmYAkKYj9gGHaij7uTejoJe9KRhNcsU4sJC1utMfhUYhg3 dialogues.py: QmQPLnW3jAs6tLLmhkX4C7texGRHM9bfdjs83dUH5TkJ4v - message.py: QmXj8MgvPtJKXZyhTnTfpXEZoAz4Z1u6wbMwMkKCRgvujL - oef_search.proto: QmfZrvXMHWTNp7QV4Vpm3TwU2h34PRHM8KkEWUVJWc7ihS - oef_search_pb2.py: QmWUYB2StNy6BqPzJjyc2WrA7y1dWFxF81m8BwRBBThDMC - serialization.py: QmdCFKKquz26fFRa3qguLgFa1GrGmCWgfLbmNmgtTSePAH + message.py: QmU8jH94qxrcr9eUtXWn5PzqmHT7NBc62gs53HPXKVk1Ts + oef_search.proto: QmNU8WsxT6XNFFneKKeDaZkNn3CEFDfZQkmKv9TyhyxzDB + oef_search_pb2.py: QmSAFT1xxYRzJU6h1aFVDuYcx672sZ2vzV6c2ico7f4BLK + serialization.py: QmVmZnv4kHr2E9UaYACiwnTuT79N4hSe7NZZ2ogB2bD2K2 fingerprint_ignore_patterns: [] dependencies: protobuf: {} diff --git a/packages/fetchai/protocols/oef_search/serialization.py b/packages/fetchai/protocols/oef_search/serialization.py index 3fbb08ce94..57a94b67be 100644 --- a/packages/fetchai/protocols/oef_search/serialization.py +++ b/packages/fetchai/protocols/oef_search/serialization.py @@ -76,6 +76,8 @@ def encode(msg: Message) -> bytes: oef_search_msg.search_result.CopyFrom(performative) elif performative_id == OefSearchMessage.Performative.SUCCESS: performative = oef_search_pb2.OefSearchMessage.Success_Performative() # type: ignore + agents_info = msg.agents_info + AgentsInfo.encode(performative.agents_info, agents_info) oef_search_msg.success.CopyFrom(performative) elif performative_id == OefSearchMessage.Performative.OEF_ERROR: performative = oef_search_pb2.OefSearchMessage.Oef_Error_Performative() # type: ignore @@ -132,7 +134,9 @@ def decode(obj: bytes) -> Message: agents_info = AgentsInfo.decode(pb2_agents_info) performative_content["agents_info"] = agents_info elif performative_id == OefSearchMessage.Performative.SUCCESS: - pass + pb2_agents_info = oef_search_pb.success.agents_info + agents_info = AgentsInfo.decode(pb2_agents_info) + performative_content["agents_info"] = agents_info elif performative_id == OefSearchMessage.Performative.OEF_ERROR: pb2_oef_error_operation = oef_search_pb.oef_error.oef_error_operation oef_error_operation = OefErrorOperation.decode(pb2_oef_error_operation) diff --git a/packages/hashes.csv b/packages/hashes.csv index 7f6099b3a0..1cde9f0754 100644 --- a/packages/hashes.csv +++ b/packages/hashes.csv @@ -28,7 +28,7 @@ fetchai/connections/p2p_libp2p,QmdhTkGsBwQ7Zrogp5eW1FcC6p1dii7TDpsmy5h9eRMxb9 fetchai/connections/p2p_libp2p_client,QmU1bNVaYjipA1uwad4CGxMgsMSNaP9n6E11SwvF2in9Jh fetchai/connections/p2p_stub,QmX8EWvFok3UAdqXGgir4TrhfDj2kLhfjuXRg82b6G6XtW fetchai/connections/scaffold,QmNUta43nLexAHaXLgmLQYEjntLXSV6MLNvc6Q2CTx7eBS -fetchai/connections/soef,QmYPr7sPQXUz2qKJ1ifomwmtUTv6aHGRdzEbuVJ1ZbzmCn +fetchai/connections/soef,QmQWyjmHg6HWsLEuighe2vrWQSKBZAXvoXSXF33XhaVyE8 fetchai/connections/stub,QmSuUAA2k1E1M9dpeAgkWpfKdssjqghSDfFfrQzC9ZLKbD fetchai/connections/tcp,QmU93B7yajCHwXsgDXXhv1uSuXi7VmFBhdahcFosbrr6nA fetchai/connections/webhook,QmaJunWQT1ypkqGnzrj5gYjjQBywjTHJmyktCZXZsa8hv8 @@ -41,7 +41,7 @@ fetchai/protocols/gym,QmVLULhH4gn8suFe8Z31X5mVYp3fFSGays5MHDNzKnGA4k fetchai/protocols/http,QmZJVqY2cxjky6p3o76TUemSsFDws8Dx33voG9WMdrKcry fetchai/protocols/ledger_api,Qmak3uKpeSfT5f4oqes3oUcNSg7vy7WKE2tUmSu8CZUNJ5 fetchai/protocols/ml_trade,QmNVZvbcgERSypYUopKMHvd6F8B81rQqtLVqUvzMeEEwJN -fetchai/protocols/oef_search,QmfKNSFNLtLimS1YSiWB9e8Ha5xUzFkFjRUXwFxELCgV41 +fetchai/protocols/oef_search,QmYjitTtVuVynTWv4TE34Wm2b37LAfyKgZEaiMfZv1jH3Z fetchai/protocols/scaffold,QmZhHsoA7JzNSoSUABFWqyRELaei4BtKYce1QKVcHhnQJN fetchai/protocols/signing,QmPhHfj2N2iCRTMEDYiifC3AkytZRFpVMoH7g63NwGcKwH fetchai/protocols/state_update,QmQmQt1VHwxmnNmwxKcrF4Qno6iHzVhhnUUjsqPtpfpQUV diff --git a/tests/test_packages/test_connections/test_soef/models.py b/tests/test_packages/test_connections/test_soef/models.py index 07107679a3..0f523d5807 100644 --- a/tests/test_packages/test_connections/test_soef/models.py +++ b/tests/test_packages/test_connections/test_soef/models.py @@ -67,3 +67,13 @@ [Attribute("location", Location, True, "The location where the agent is.")], "A data model to perform search.", ) + + +AGENT_GENERIC_COMMAND_MODEL = DataModel( + ModelNames.generic_command, + [ + Attribute("command", str, True, "Command name to execute."), + Attribute("parameters", str, False, "Url encoded parameters string."), + ], + "A data model to describe the generic soef command.", +) diff --git a/tests/test_packages/test_connections/test_soef/test_soef_integration.py b/tests/test_packages/test_connections/test_soef/test_soef_integration.py index c832ea510e..d739796356 100644 --- a/tests/test_packages/test_connections/test_soef/test_soef_integration.py +++ b/tests/test_packages/test_connections/test_soef/test_soef_integration.py @@ -16,13 +16,15 @@ # limitations under the License. # # ------------------------------------------------------------------------------ - """This module contains the tests of the soef connection module.""" import logging import time from threading import Thread from typing import Any, Dict, Optional, Tuple, cast +from urllib.parse import urlencode + +from defusedxml import ElementTree as ET # pylint: disable=wrong-import-order import pytest @@ -187,16 +189,43 @@ def search(self, query: Query) -> OefSearchMessage: ) logger.info(f"Searching for agents with query: {query}") self.multiplexer.put(search_envelope) - wait_for_condition(lambda: not self.multiplexer.in_queue.empty(), timeout=20) # check for search results - envelope = self.multiplexer.get() + envelope = self.get() assert envelope message = cast(OefSearchMessage, envelope.message) receiving_dialogue = self.oef_search_dialogues.update(message) assert sending_dialogue == receiving_dialogue return message + def get(self): + wait_for_condition(lambda: not self.multiplexer.in_queue.empty(), timeout=20) + return self.multiplexer.get() + + def generic_command(self, command: str, parameters: Optional[dict] = None) -> None: + """Register personality pieces.""" + service_instance = {"command": command} + + if parameters: + service_instance["parameters"] = urlencode(parameters) + + service_description = Description( + service_instance, data_model=models.AGENT_GENERIC_COMMAND_MODEL + ) + message, _ = self.oef_search_dialogues.create( + counterparty=SOEFConnection.connection_id.latest, + performative=OefSearchMessage.Performative.REGISTER_SERVICE, + service_description=service_description, + ) + envelope = Envelope( + to=message.to, + sender=message.sender, + protocol_id=message.protocol_id, + message=message, + ) + logger.info(f"Send generic command {command} {parameters}") + self.multiplexer.put(envelope) + class TestRealNetwork: """Perform tests using real soef server.""" @@ -328,3 +357,27 @@ def test_ping(self): finally: agent.stop() + + @pytest.mark.integration + def test_generic_command(self): + """Test generic command.""" + agent_location = Location(*self.LOCATION) + agent = Instance(agent_location) + agent.start() + + try: + agent.generic_command("set_service_key", {"key": "test", "value": "test"}) + envelope = agent.get() + assert ( + envelope.message.performative == OefSearchMessage.Performative.SUCCESS + ) + ET.fromstring(envelope.message.agents_info.body["response"]["content"]) + + agent.generic_command("bad_command") + envelope = agent.get() + assert ( + envelope.message.performative == OefSearchMessage.Performative.OEF_ERROR + ) + + finally: + agent.stop() diff --git a/tests/test_packages/test_protocols/test_oef_search.py b/tests/test_packages/test_protocols/test_oef_search.py index abd1250f66..6c73e6d1e1 100644 --- a/tests/test_packages/test_protocols/test_oef_search.py +++ b/tests/test_packages/test_protocols/test_oef_search.py @@ -179,7 +179,15 @@ def test_search_result_serialization(): def test_success_serialization(): """Test the serialization for 'success' speech-act works.""" - msg = OefSearchMessage(performative=OefSearchMessage.Performative.SUCCESS,) + msg = OefSearchMessage( + performative=OefSearchMessage.Performative.SUCCESS, + agents_info=OefSearchMessage.AgentsInfo( + { + "key_1": {"key_1": b"value_1", "key_2": b"value_2"}, + "key_2": {"key_3": b"value_3", "key_4": b"value_4"}, + } + ), + ) msg.to = "receiver" envelope = Envelope( to=msg.to,