def test_search_services_with_query_with_model(self): """Test that a search services request can be sent correctly. In this test, the query has a simple data model. """ request_id = 2 data_model = DataModel("foobar", [Attribute("foo", str, True)]) search_query = Query( [Constraint("foo", ConstraintType("==", "bar"))], model=data_model) search_request = OEFMessage( oef_type=OEFMessage.Type.SEARCH_SERVICES, id=request_id, query=search_query) self.mailbox1.outbox.put_message( to=DEFAULT_OEF, sender=self.crypto1.public_key, protocol_id=OEFMessage.protocol_id, message=OEFSerializer().encode(search_request)) envelope = self.mailbox1.inbox.get(block=True, timeout=5.0) search_result = OEFSerializer().decode(envelope.message) assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT assert search_result.get("id") == request_id assert search_result.get("agents") == []
def handle_envelope(self, envelope: Envelope) -> None: """ Implement the reaction to an envelope. :param envelope: the envelope :return: None """ msg = OEFSerializer().decode(envelope.message) msg_type = OEFMessage.Type(msg.get("type")) if msg_type is OEFMessage.Type.SEARCH_RESULT: agents = cast(List[str], msg.get("agents")) logger.info("[{}]: found agents={}".format(self.context.agent_name, agents)) for agent in agents: msg = FIPAMessage(message_id=STARTING_MESSAGE_ID, dialogue_id=self.dialogue_id, performative=FIPAMessage.Performative.CFP, target=STARTING_TARGET_ID, query=None) self.dialogue_id += 1 self.context.outbox.put_message( to=agent, sender=self.context.agent_public_key, protocol_id=FIPAMessage.protocol_id, message=FIPASerializer().encode(msg))
def test_register_service(self): """Test that a register service request works correctly.""" foo_datamodel = DataModel( "foo", [Attribute("bar", int, True, "A bar attribute.")]) desc = Description({"bar": 1}, data_model=foo_datamodel) msg = OEFMessage(oef_type=OEFMessage.Type.REGISTER_SERVICE, id=1, service_description=desc, service_id="") msg_bytes = OEFSerializer().encode(msg) self.mailbox1.outbox.put_message( to=DEFAULT_OEF, sender=self.crypto1.public_key, protocol_id=OEFMessage.protocol_id, message=msg_bytes) search_request = OEFMessage( oef_type=OEFMessage.Type.SEARCH_SERVICES, id=2, query=Query([Constraint("bar", ConstraintType("==", 1))], model=foo_datamodel)) self.mailbox1.outbox.put_message( to=DEFAULT_OEF, sender=self.crypto1.public_key, protocol_id=OEFMessage.protocol_id, message=OEFSerializer().encode(search_request)) envelope = self.mailbox1.inbox.get(block=True, timeout=5.0) search_result = OEFSerializer().decode(envelope.message) assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT assert search_result.get("id") == 2 assert search_result.get("agents") == [self.crypto1.public_key]
def handle_oef_message(self, envelope: Envelope) -> None: """ Handle messages from the oef. The oef does not expect a response for any of these messages. :param envelope: the OEF message :return: None """ logger.debug( "[{}]: Handling OEF message. type={}".format( self.agent_name, type(envelope) ) ) assert envelope.protocol_id == "oef" msg = OEFSerializer().decode(envelope.message) if msg.get("type") == OEFMessage.Type.OEF_ERROR: self.on_oef_error(envelope) elif msg.get("type") == OEFMessage.Type.DIALOGUE_ERROR: self.on_dialogue_error(envelope) else: logger.warning( "[{}]: OEF Message type not recognized.".format(self.agent_name) )
def test_empty_search_result(self): """Test that at the beginning, the search request returns an empty search result.""" request_id = 1 query = Query(constraints=[], model=None) # build and send the request search_services_request = OEFMessage( oef_type=OEFMessage.Type.SEARCH_SERVICES, id=request_id, query=query) msg_bytes = OEFSerializer().encode(search_services_request) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.mailbox1.send(envelope) # check the result response_envelope = self.mailbox1.inbox.get(block=True, timeout=2.0) assert response_envelope.protocol_id == OEFMessage.protocol_id assert response_envelope.to == self.public_key_1 assert response_envelope.sender == DEFAULT_OEF search_result = OEFSerializer().decode(response_envelope.message) assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT assert search_result.get("agents") == []
def test_unregister_service_result(self): """Test that at the beginning, the search request returns an empty search result.""" data_model = DataModel("foobar", attributes=[]) service_description = Description({"foo": 1, "bar": "baz"}, data_model=data_model) msg = OEFMessage(oef_type=OEFMessage.Type.UNREGISTER_SERVICE, id=0, service_description=service_description, service_id="Test_service") msg_bytes = OEFSerializer().encode(msg) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.multiplexer1.put(envelope) # check the result response_envelope = self.multiplexer1.get(block=True, timeout=5.0) assert response_envelope.protocol_id == OEFMessage.protocol_id assert response_envelope.sender == DEFAULT_OEF result = OEFSerializer().decode(response_envelope.message) assert result.get("type") == OEFMessage.Type.OEF_ERROR msg = OEFMessage(oef_type=OEFMessage.Type.REGISTER_SERVICE, id=0, service_description=service_description, service_id="Test_Service") msg_bytes = OEFSerializer().encode(msg) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.multiplexer1.put(envelope) # Search for the register agent msg = OEFMessage(oef_type=OEFMessage.Type.SEARCH_AGENTS, id=0, query=Query([Constraint("foo", ConstraintType("==", 1))])) msg_bytes = OEFSerializer().encode(msg) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.multiplexer1.put(envelope) # check the result response_envelope = self.multiplexer1.get(block=True, timeout=5.0) assert response_envelope.protocol_id == OEFMessage.protocol_id assert response_envelope.sender == DEFAULT_OEF result = OEFSerializer().decode(response_envelope.message) assert result.get("type") == OEFMessage.Type.SEARCH_RESULT assert len(result.get("agents")) == 1 # unregister the service data_model = DataModel("foobar", attributes=[]) service_description = Description({"foo": 1, "bar": "baz"}, data_model=data_model) msg = OEFMessage(oef_type=OEFMessage.Type.UNREGISTER_SERVICE, id=0, service_description=service_description, service_id="Test_service") msg_bytes = OEFSerializer().encode(msg) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.multiplexer1.put(envelope) # the same query returns empty # Search for the register agent msg = OEFMessage(oef_type=OEFMessage.Type.SEARCH_AGENTS, id=0, query=Query([Constraint("foo", ConstraintType("==", 1))])) msg_bytes = OEFSerializer().encode(msg) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.multiplexer1.put(envelope) # check the result response_envelope = self.multiplexer1.get(block=True, timeout=5.0) assert response_envelope.protocol_id == OEFMessage.protocol_id assert response_envelope.sender == DEFAULT_OEF result = OEFSerializer().decode(response_envelope.message) assert result.get("type") == OEFMessage.Type.SEARCH_RESULT assert len(result.get("agents")) == 0
def on_oef_error(self, envelope: Envelope) -> None: """ Handle an OEF error message. :param envelope: the oef error :return: None """ oef_error = OEFSerializer().decode(envelope.message) logger.error( "[{}]: Received OEF error: answer_id={}, operation={}".format( self.agent_name, oef_error.get("id"), oef_error.get("operation")))
def setup_class(cls): """ Set the test up. Steps: - Register a service - Check that the registration worked. """ cls.crypto1 = DefaultCrypto() cls.connection = OEFConnection(cls.crypto1.public_key, oef_addr="127.0.0.1", oef_port=10000) cls.multiplexer = Multiplexer([cls.connection]) cls.multiplexer.connect() cls.request_id = 1 cls.foo_datamodel = DataModel( "foo", [Attribute("bar", int, True, "A bar attribute.")]) cls.desc = Description({"bar": 1}, data_model=cls.foo_datamodel) msg = OEFMessage(oef_type=OEFMessage.Type.REGISTER_SERVICE, id=cls.request_id, service_description=cls.desc, service_id="") msg_bytes = OEFSerializer().encode(msg) cls.multiplexer.put( Envelope(to=DEFAULT_OEF, sender=cls.crypto1.public_key, protocol_id=OEFMessage.protocol_id, message=msg_bytes)) time.sleep(1.0) cls.request_id += 1 search_request = OEFMessage( oef_type=OEFMessage.Type.SEARCH_SERVICES, id=cls.request_id, query=Query([Constraint("bar", ConstraintType("==", 1))], model=cls.foo_datamodel)) cls.multiplexer.put( Envelope(to=DEFAULT_OEF, sender=cls.crypto1.public_key, protocol_id=OEFMessage.protocol_id, message=OEFSerializer().encode(search_request))) envelope = cls.multiplexer.get(block=True, timeout=5.0) search_result = OEFSerializer().decode(envelope.message) assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT assert search_result.get("id") == cls.request_id if search_result.get("agents") != [cls.crypto1.public_key]: logger.warning( 'search_result.get("agents") != [self.crypto1.public_key] FAILED in test_oef/test_communication.py' )
async def _handle_oef_message(self, envelope: Envelope) -> None: """Handle oef messages. :param envelope: the envelope :return: None """ oef_message = OEFSerializer().decode(envelope.message) sender = envelope.sender request_id = cast(int, oef_message.get("id")) oef_type = OEFMessage.Type(oef_message.get("type")) if oef_type == OEFMessage.Type.REGISTER_SERVICE: await self._register_service( sender, cast(Description, oef_message.get("service_description"))) elif oef_type == OEFMessage.Type.REGISTER_AGENT: await self._register_agent( sender, cast(Description, oef_message.get("agent_description"))) elif oef_type == OEFMessage.Type.UNREGISTER_SERVICE: await self._unregister_service( sender, request_id, cast(Description, oef_message.get("service_description"))) elif oef_type == OEFMessage.Type.UNREGISTER_AGENT: await self._unregister_agent( sender, request_id, cast(Description, oef_message.get("agent_description"))) elif oef_type == OEFMessage.Type.SEARCH_AGENTS: await self._search_agents(sender, request_id, cast(Query, oef_message.get("query"))) elif oef_type == OEFMessage.Type.SEARCH_SERVICES: await self._search_services(sender, request_id, cast(Query, oef_message.get("query"))) else: # request not recognized pass
def test_search_agent(self): """Test the registered agents, we will not find any.""" data_model = DataModel("foobar", attributes=[]) agent_description = Description({"foo": 1, "bar": "baz"}, data_model=data_model) query = Query(constraints=[], model=data_model) # Register an agent msg = OEFMessage(oef_type=OEFMessage.Type.REGISTER_AGENT, id=0, agent_description=agent_description, agent_id="Test_agent") msg_bytes = OEFSerializer().encode(msg) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.multiplexer1.put(envelope) time.sleep(0.1) # Search for the register agent msg = OEFMessage(oef_type=OEFMessage.Type.SEARCH_AGENTS, id=0, query=query) msg_bytes = OEFSerializer().encode(msg) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_2, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.multiplexer2.put(envelope) # check the result response_envelope = self.multiplexer2.get(block=True, timeout=5.0) assert response_envelope.protocol_id == OEFMessage.protocol_id assert response_envelope.sender == DEFAULT_OEF result = OEFSerializer().decode(response_envelope.message) assert len(result.get("agents")) == 1, "There are registered agents!" # Send unregister message. msg = OEFMessage(oef_type=OEFMessage.Type.UNREGISTER_AGENT, id=0, agent_description=agent_description, agent_id="Test_agent") msg_bytes = OEFSerializer().encode(msg) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.multiplexer1.put(envelope) time.sleep(0.1) # Trigger error message. msg = OEFMessage(oef_type=OEFMessage.Type.UNREGISTER_AGENT, id=0, agent_description=agent_description, agent_id="Unknown_Agent") msg_bytes = OEFSerializer().encode(msg) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.multiplexer1.put(envelope) # check the result response_envelope = self.multiplexer1.get(block=True, timeout=5.0) assert response_envelope.protocol_id == OEFMessage.protocol_id assert response_envelope.sender == DEFAULT_OEF result = OEFSerializer().decode(response_envelope.message) assert result.get("type") == OEFMessage.Type.OEF_ERROR
def on_dialogue_error(self, envelope: Envelope) -> None: """ Handle a dialogue error message. :param envelope: the dialogue error message :return: None """ dialogue_error = OEFSerializer().decode(envelope.message) logger.error( "[{}]: Received Dialogue error: answer_id={}, dialogue_id={}, origin={}" .format(self.agent_name, dialogue_error.get("id"), dialogue_error.get("dialogue_id"), dialogue_error.get("origin")))
def test_not_empty_search_result(self): """Test that the search result contains one entry after a successful registration.""" request_id = 1 query = Query(constraints=[], model=self.data_model) # build and send the request search_services_request = OEFMessage(oef_type=OEFMessage.Type.SEARCH_SERVICES, id=request_id, query=query) msg_bytes = OEFSerializer().encode(search_services_request) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.multiplexer.put(envelope) # check the result response_envelope = self.multiplexer.get(block=True, timeout=2.0) assert response_envelope.protocol_id == OEFMessage.protocol_id assert response_envelope.to == self.public_key_1 assert response_envelope.sender == DEFAULT_OEF search_result = OEFSerializer().decode(response_envelope.message) assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT assert search_result.get("agents") == [self.public_key_1]
def test_filtered_search_result(self): """Test that the search result contains only the entries matching the query.""" request_id = 1 query = Query(constraints=[], model=self.data_model_barfoo) # build and send the request search_services_request = OEFMessage(oef_type=OEFMessage.Type.SEARCH_SERVICES, id=request_id, query=query) msg_bytes = OEFSerializer().encode(search_services_request) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=OEFMessage.protocol_id, message=msg_bytes) self.multiplexer1.put(envelope) # check the result response_envelope = InBox(self.multiplexer1).get(block=True, timeout=5.0) assert response_envelope.protocol_id == OEFMessage.protocol_id assert response_envelope.to == self.public_key_1 assert response_envelope.sender == DEFAULT_OEF search_result = OEFSerializer().decode(response_envelope.message) assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT assert search_result.get("agents") == [self.public_key_2]
def test_on_dialogue_error(self): """Test the dialogue error.""" oef_connection = self.multiplexer1.connections[0] oef_channel = oef_connection.channel oef_channel.on_dialogue_error(answer_id=0, dialogue_id=0, origin="me") envelope = self.multiplexer1.get(block=True, timeout=5.0) dec_msg = OEFSerializer().decode(envelope.message) assert dec_msg.get( "type" ) is OEFMessage.Type.DIALOGUE_ERROR, "It should be a dialogue error"
def test_search_count_increases(self): """Test that the search count increases.""" request_id = 1 search_query_empty_model = Query( [Constraint("foo", ConstraintType("==", "bar"))], model=None) search_request = OEFMessage( oef_type=OEFMessage.Type.SEARCH_SERVICES, id=request_id, query=search_query_empty_model) self.multiplexer.put( Envelope(to=DEFAULT_OEF, sender=self.crypto1.public_key, protocol_id=OEFMessage.protocol_id, message=OEFSerializer().encode(search_request))) envelope = self.multiplexer.get(block=True, timeout=5.0) search_result = OEFSerializer().decode(envelope.message) assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT assert search_result.get("id") assert request_id and search_result.get("agents") == []
def test_on_oef_error(self): """Test the oef error.""" oef_connection = self.multiplexer1.connections[0] oef_channel = oef_connection.channel oef_channel.on_oef_error(answer_id=0, operation=OEFErrorOperation.SEARCH_AGENTS) envelope = self.multiplexer1.get(block=True, timeout=5.0) dec_msg = OEFSerializer().decode(envelope.message) assert dec_msg.get( "type" ) is OEFMessage.Type.OEF_ERROR, "It should be an error message"
def test_unregister_service(self): """Test that an unregister service request works correctly. Steps: 2. unregister the service 3. search for that service 4. assert that no result is found. """ self.request_id += 1 msg = OEFMessage(oef_type=OEFMessage.Type.UNREGISTER_SERVICE, id=self.request_id, service_description=self.desc, service_id="") msg_bytes = OEFSerializer().encode(msg) self.mailbox1.outbox.put_message( to=DEFAULT_OEF, sender=self.crypto1.public_key, protocol_id=OEFMessage.protocol_id, message=msg_bytes) time.sleep(1.0) self.request_id += 1 search_request = OEFMessage( oef_type=OEFMessage.Type.SEARCH_SERVICES, id=self.request_id, query=Query([Constraint("bar", ConstraintType("==", 1))], model=self.foo_datamodel)) self.mailbox1.outbox.put_message( to=DEFAULT_OEF, sender=self.crypto1.public_key, protocol_id=OEFMessage.protocol_id, message=OEFSerializer().encode(search_request)) envelope = self.mailbox1.inbox.get(block=True, timeout=5.0) search_result = OEFSerializer().decode(envelope.message) assert search_result.get("type") == OEFMessage.Type.SEARCH_RESULT assert search_result.get("id") == self.request_id assert search_result.get("agents") == []
def handle_envelope(self, envelope: Envelope) -> None: """ Implement the reaction to an envelope. :param envelope: the envelope :return: None """ oef_message = OEFSerializer().decode(envelope.message) oef_type = oef_message.get("type") logger.debug("[{}]: Handling OEF message. type={}".format(self.context.agent_name, oef_type)) oef_message = cast(OEFMessage, oef_message) if oef_type == OEFMessage.Type.SEARCH_RESULT: self._on_search_result(oef_message) elif oef_type == OEFMessage.Type.OEF_ERROR: self._on_oef_error(oef_message) elif oef_type == OEFMessage.Type.DIALOGUE_ERROR: self._on_dialogue_error(oef_message)
async def test_messages(self): """Test that at the beginning, the search request returns an empty search result.""" msg = FIPAMessage((str(0), ''), 0, 0, FIPAMessage.Performative.CFP, query=None) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to=DEFAULT_OEF, sender=self.public_key_1, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) with pytest.raises(AEAConnectionError): await OEFLocalConnection(self.public_key_1, self.node).send(envelope) self.multiplexer1.connect() msg = FIPAMessage((str(0), str(1)), 0, 0, FIPAMessage.Performative.CFP, query=None) msg_bytes = FIPASerializer().encode(msg) envelope = Envelope(to="this_public_key_does_not_exist", sender=self.public_key_1, protocol_id=FIPAMessage.protocol_id, message=msg_bytes) self.multiplexer1.put(envelope) # check the result response_envelope = self.multiplexer1.get(block=True, timeout=5.0) assert response_envelope.protocol_id == OEFMessage.protocol_id assert response_envelope.sender == DEFAULT_OEF result = OEFSerializer().decode(response_envelope.message) assert result.get("type") == OEFMessage.Type.DIALOGUE_ERROR
def send_oef_message(self, envelope: Envelope) -> None: """ Send oef message handler. :param envelope: the message. :return: None """ oef_message = OEFSerializer().decode(envelope.message) oef_type = OEFMessage.Type(oef_message.get("type")) oef_msg_id = cast(int, oef_message.get("id")) if oef_type == OEFMessage.Type.REGISTER_SERVICE: service_description = cast(Description, oef_message.get("service_description")) service_id = cast(int, oef_message.get("service_id")) oef_service_description = OEFObjectTranslator.to_oef_description( service_description) self.register_service(oef_msg_id, oef_service_description, service_id) elif oef_type == OEFMessage.Type.UNREGISTER_SERVICE: service_description = cast(Description, oef_message.get("service_description")) service_id = cast(int, oef_message.get("service_id")) oef_service_description = OEFObjectTranslator.to_oef_description( service_description) self.unregister_service(oef_msg_id, oef_service_description, service_id) elif oef_type == OEFMessage.Type.SEARCH_AGENTS: query = cast(Query, oef_message.get("query")) oef_query = OEFObjectTranslator.to_oef_query(query) self.search_agents(oef_msg_id, oef_query) elif oef_type == OEFMessage.Type.SEARCH_SERVICES: query = cast(Query, oef_message.get("query")) oef_query = OEFObjectTranslator.to_oef_query(query) self.mail_stats.search_start(oef_msg_id) self.search_services(oef_msg_id, oef_query) else: raise ValueError("OEF request not recognized.")