示例#1
0
    def setup(self):
        """Set up."""
        self.crypto = make_crypto(DEFAULT_LEDGER)
        self.crypto2 = make_crypto(DEFAULT_LEDGER)
        identity = Identity("", address=self.crypto.address)
        self.oef_search_dialogues = OefSearchDialogues(self.crypto.address)
        self.data_dir = tempfile.mkdtemp()

        # create the connection and multiplexer objects
        configuration = ConnectionConfig(
            api_key="TwiCIriSl0mLahw17pyqoA",
            soef_addr="s-oef.fetch.ai",
            soef_port=443,
            restricted_to_protocols={
                OefSearchMessage.protocol_specification_id
            },
            connection_id=SOEFConnection.connection_id,
        )
        self.connection = SOEFConnection(
            configuration=configuration,
            data_dir=self.data_dir,
            identity=identity,
        )
        self.connection2 = SOEFConnection(
            configuration=configuration,
            data_dir=self.data_dir,
            identity=Identity("", address=self.crypto2.address),
        )
        self.loop = asyncio.get_event_loop()
        self.loop.run_until_complete(self.connection.connect())
        self.loop.run_until_complete(self.connection2.connect())
        self.connection.channel.unique_page_address = "some_addr"
示例#2
0
    def setup(self):
        """Set up."""
        self.crypto = make_crypto(DEFAULT_LEDGER)
        self.crypto2 = make_crypto(DEFAULT_LEDGER)
        identity = Identity("", address=self.crypto.address)
        self.oef_search_dialogues = OefSearchDialogues(self.crypto.address)

        # create the connection and multiplexer objects
        configuration = ConnectionConfig(
            api_key="TwiCIriSl0mLahw17pyqoA",
            soef_addr="soef.fetch.ai",
            soef_port=9002,
            restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
            connection_id=SOEFConnection.connection_id,
        )
        self.connection = SOEFConnection(
            configuration=configuration, identity=identity,
        )
        self.connection.channel.unique_page_address = "some addr"
        self.connection2 = SOEFConnection(
            configuration=configuration,
            identity=Identity("", address=self.crypto2.address),
        )
        self.loop = asyncio.get_event_loop()
        self.loop.run_until_complete(self.connection.connect())
        self.loop.run_until_complete(self.connection2.connect())
示例#3
0
def make_multiplexer_and_dialogues(
) -> Tuple[Multiplexer, OefSearchDialogues, Crypto, SOEFConnection]:
    """Return multplexer, dialogues and crypto instances."""
    crypto = make_crypto(DEFAULT_LEDGER)
    identity = Identity("", address=crypto.address)
    oef_search_dialogues = OefSearchDialogues(crypto.address)

    # create the connection and multiplexer objects
    configuration = ConnectionConfig(
        api_key="TwiCIriSl0mLahw17pyqoA",
        soef_addr="s-oef.fetch.ai",
        soef_port=443,
        restricted_to_protocols={
            OefSearchMessage.protocol_specification_id,
            OefSearchMessage.protocol_id,
        },
        connection_id=SOEFConnection.connection_id,
    )
    soef_connection = SOEFConnection(
        configuration=configuration,
        data_dir=MagicMock(),
        identity=identity,
    )
    multiplexer = Multiplexer([soef_connection])
    return multiplexer, oef_search_dialogues, crypto, soef_connection
示例#4
0
    def setup(self):
        """Set up."""
        self.crypto = make_crypto(DEFAULT_LEDGER)
        self.crypto2 = make_crypto(DEFAULT_LEDGER)
        self.data_dir = tempfile.mkdtemp()
        identity = Identity("", address=self.crypto.address)
        self.oef_search_dialogues = OefSearchDialogues(self.crypto.address)

        # create the connection and multiplexer objects
        self.token_storage_path = "test.storage"
        configuration = ConnectionConfig(
            api_key="TwiCIriSl0mLahw17pyqoA",
            soef_addr="s-oef.fetch.ai",
            soef_port=443,
            token_storage_path=self.token_storage_path,
            restricted_to_protocols={
                OefSearchMessage.protocol_specification_id
            },
            connection_id=SOEFConnection.connection_id,
        )
        self.connection = SOEFConnection(
            configuration=configuration,
            data_dir=self.data_dir,
            identity=identity,
        )
示例#5
0
    def test_chain_identifier_ok(self):
        """Test set valid chain id."""
        chain_identifier = "fetchai_cosmos"
        identity = Identity("", "")

        configuration = ConnectionConfig(
            api_key="TwiCIriSl0mLahw17pyqoA",
            soef_addr="soef.fetch.ai",
            soef_port=9002,
            restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
            connection_id=SOEFConnection.connection_id,
            chain_identifier=chain_identifier,
        )
        connection = SOEFConnection(configuration=configuration, identity=identity,)

        assert connection.channel.chain_identifier == chain_identifier
示例#6
0
    def test_chain_identifier_fail(self):
        """Test fail on invalid chain id."""
        chain_identifier = "test"
        identity = Identity("", "")

        configuration = ConnectionConfig(
            api_key="TwiCIriSl0mLahw17pyqoA",
            soef_addr="soef.fetch.ai",
            soef_port=9002,
            restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
            connection_id=SOEFConnection.connection_id,
            chain_identifier=chain_identifier,
        )
        with pytest.raises(ValueError, match="Unsupported chain_identifier"):
            SOEFConnection(
                configuration=configuration, identity=identity,
            )
示例#7
0
    def test_chain_identifier_fail(self):
        """Test fail on invalid chain id."""
        chain_identifier = "test"
        identity = Identity("", "")

        configuration = ConnectionConfig(
            api_key="TwiCIriSl0mLahw17pyqoA",
            soef_addr="s-oef.fetch.ai",
            soef_port=443,
            restricted_to_protocols={
                OefSearchMessage.protocol_specification_id
            },
            connection_id=SOEFConnection.connection_id,
            chain_identifier=chain_identifier,
        )
        with pytest.raises(ValueError, match="Unsupported chain_identifier"):
            SOEFConnection(
                configuration=configuration,
                data_dir=MagicMock(),
                identity=identity,
            )
示例#8
0
    def test_chain_identifier_ok(self):
        """Test set valid chain id."""
        chain_identifier = "fetchai_cosmos"
        identity = Identity("", "")

        configuration = ConnectionConfig(
            api_key="TwiCIriSl0mLahw17pyqoA",
            soef_addr="s-oef.fetch.ai",
            soef_port=443,
            restricted_to_protocols={
                OefSearchMessage.protocol_specification_id
            },
            connection_id=SOEFConnection.connection_id,
            chain_identifier=chain_identifier,
        )
        connection = SOEFConnection(
            configuration=configuration,
            data_dir=MagicMock(),
            identity=identity,
        )

        assert connection.channel.chain_identifier == chain_identifier
示例#9
0
def test_soef():
    """Perform tests over real network."""
    # First run OEF in a separate terminal: python scripts/oef/launch.py -c ./scripts/oef/launch_config.json
    crypto = FetchAICrypto()
    identity = Identity("", address=crypto.address)

    # create the connection and multiplexer objects
    configuration = ConnectionConfig(
        api_key="TwiCIriSl0mLahw17pyqoA",
        soef_addr="soef.fetch.ai",
        soef_port=9002,
        restricted_to_protocols={
            PublicId.from_str("fetchai/oef_search:0.3.0")
        },
        connection_id=SOEFConnection.connection_id,
    )
    soef_connection = SOEFConnection(
        configuration=configuration,
        identity=identity,
    )
    multiplexer = Multiplexer([soef_connection])

    try:
        # Set the multiplexer running in a different thread
        t = Thread(target=multiplexer.connect)
        t.start()

        wait_for_condition(lambda: multiplexer.is_connected, timeout=5)

        # register an agent with location
        agent_location = Location(52.2057092, 2.1183431)
        service_instance = {"location": agent_location}
        service_description = Description(
            service_instance, data_model=models.AGENT_LOCATION_MODEL)
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.REGISTER_SERVICE,
            service_description=service_description,
        )
        envelope = Envelope(
            to="soef",
            sender=crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )
        logger.info("Registering agent at location=({},{}) by agent={}".format(
            agent_location.latitude,
            agent_location.longitude,
            crypto.address,
        ))
        multiplexer.put(envelope)

        # register personality pieces
        service_instance = {"piece": "genus", "value": "service"}
        service_description = Description(
            service_instance, data_model=models.AGENT_PERSONALITY_MODEL)
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.REGISTER_SERVICE,
            service_description=service_description,
        )
        envelope = Envelope(
            to="soef",
            sender=crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )
        logger.info("Registering agent personality")
        multiplexer.put(envelope)

        # register service key
        service_instance = {"key": "test", "value": "test"}
        service_description = Description(
            service_instance, data_model=models.SET_SERVICE_KEY_MODEL)
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.REGISTER_SERVICE,
            service_description=service_description,
        )
        envelope = Envelope(
            to="soef",
            sender=crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )
        logger.info("Registering agent service key")
        multiplexer.put(envelope)

        # find agents near me
        radius = 0.1
        close_to_my_service = Constraint(
            "location", ConstraintType("distance", (agent_location, radius)))
        closeness_query = Query([close_to_my_service],
                                model=models.AGENT_LOCATION_MODEL)
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.SEARCH_SERVICES,
            query=closeness_query,
        )
        envelope = Envelope(
            to="soef",
            sender=crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )
        logger.info(
            "Searching for agents in radius={} of myself at location=({},{})".
            format(
                radius,
                agent_location.latitude,
                agent_location.longitude,
            ))
        multiplexer.put(envelope)
        wait_for_condition(lambda: not multiplexer.in_queue.empty(),
                           timeout=20)

        # check for search results
        envelope = multiplexer.get()
        message = envelope.message
        assert len(message.agents) >= 0

        # find agents near me with filter
        radius = 0.1
        close_to_my_service = Constraint(
            "location", ConstraintType("distance", (agent_location, radius)))
        personality_filters = [
            Constraint("genus", ConstraintType("==", "vehicle")),
            Constraint("classification",
                       ConstraintType("==", "mobility.railway.train")),
        ]

        service_key_filters = [
            Constraint("test", ConstraintType("==", "test")),
        ]

        closeness_query = Query([close_to_my_service] + personality_filters +
                                service_key_filters)

        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.SEARCH_SERVICES,
            query=closeness_query,
        )
        envelope = Envelope(
            to="soef",
            sender=crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )
        logger.info(
            "Searching for agents in radius={} of myself at location=({},{}) with personality filters"
            .format(
                radius,
                agent_location.latitude,
                agent_location.longitude,
            ))
        time.sleep(3)  # cause requests rate limit on server :(
        multiplexer.put(envelope)
        wait_for_condition(lambda: not multiplexer.in_queue.empty(),
                           timeout=20)

        envelope = multiplexer.get()
        message = envelope.message
        assert len(message.agents) >= 0

        # test ping command
        service_description = Description({}, data_model=models.PING_MODEL)
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.REGISTER_SERVICE,
            service_description=service_description,
        )
        envelope = Envelope(
            to="soef",
            sender=crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )
        logger.info("Registering agent service key")
        multiplexer.put(envelope)
        time.sleep(3)
        assert multiplexer.in_queue.empty()

    finally:
        # Shut down the multiplexer
        multiplexer.disconnect()
        t.join()
示例#10
0
class TestSoef:
    """Set of unit tests for soef connection."""

    search_success_response = """<?xml version="1.0" encoding="UTF-8"?><response><success>1</success><total>2</total><capped>0</capped><results><agent name="8c25cc02fd0c45f8895a3d4b3895376a" genus="" classification=""><identities><identity chain_identifier="fetchai">2ayYmgrCg76R1mzr2zWCmivzJG31hXtFVwQvR4XrXrD88Rc3sT</identity></identities><range_in_km>0</range_in_km></agent><agent name="9b61f3d2217b4d4f995e779db775fbdd" genus="" classification=""><identities><identity chain_identifier="fetchai">2DvN8QNXKE2tjnKgMKvBy9ZFyC6JaFYFrcLyWSS4A9RDWeTP4k</identity></identities><range_in_km>0</range_in_km></agent></results></response>"""
    search_empty_response = """<?xml version="1.0" encoding="UTF-8"?><response><success>1</success><total>0</total><capped>0</capped><results></results></response>"""
    search_fail_response = (
        """<?xml version="1.0" encoding="UTF-8"?><notaresponse></notaresponse>"""
    )
    generic_success_response = """<?xml version="1.0" encoding="UTF-8"?><response><success>1</success></response>"""

    def setup(self):
        """Set up."""
        self.crypto = make_crypto(DEFAULT_LEDGER)
        self.crypto2 = make_crypto(DEFAULT_LEDGER)
        identity = Identity("", address=self.crypto.address)
        self.oef_search_dialogues = OefSearchDialogues(self.crypto.address)

        # create the connection and multiplexer objects
        configuration = ConnectionConfig(
            api_key="TwiCIriSl0mLahw17pyqoA",
            soef_addr="soef.fetch.ai",
            soef_port=9002,
            restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
            connection_id=SOEFConnection.connection_id,
        )
        self.connection = SOEFConnection(
            configuration=configuration, identity=identity,
        )
        self.connection.channel.unique_page_address = "some addr"
        self.connection2 = SOEFConnection(
            configuration=configuration,
            identity=Identity("", address=self.crypto2.address),
        )
        self.loop = asyncio.get_event_loop()
        self.loop.run_until_complete(self.connection.connect())
        self.loop.run_until_complete(self.connection2.connect())

    @pytest.mark.asyncio
    async def test_set_service_key(self):
        """Test set service key."""
        service_instance = {"key": "test", "value": "test"}
        service_description = Description(
            service_instance, data_model=models.SET_SERVICE_KEY_MODEL
        )
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.REGISTER_SERVICE,
            dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
            service_description=service_description,
        )
        message.counterparty = SOEFConnection.connection_id.latest
        sending_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue is not None
        envelope = Envelope(
            to=message.counterparty,
            sender=self.crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )

        with patch.object(
            self.connection.channel,
            "_request_text",
            make_async(self.generic_success_response),
        ):
            await self.connection.send(envelope)

        with pytest.raises(asyncio.TimeoutError):  # got no message back
            await asyncio.wait_for(self.connection.receive(), timeout=1)

    @pytest.mark.asyncio
    async def test_remove_service_key(self):
        """Test remove service key."""
        await self.test_set_service_key()
        service_instance = {"key": "test"}
        service_description = Description(
            service_instance, data_model=models.REMOVE_SERVICE_KEY_MODEL
        )
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
            dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
            service_description=service_description,
        )
        message.counterparty = SOEFConnection.connection_id.latest
        sending_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue is not None
        envelope = Envelope(
            to=message.counterparty,
            sender=self.crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )

        with patch.object(
            self.connection.channel,
            "_request_text",
            make_async(self.generic_success_response),
        ):
            await self.connection.send(envelope)

        with pytest.raises(asyncio.TimeoutError):  # got no message back
            await asyncio.wait_for(self.connection.receive(), timeout=1)

    def test_connected(self):
        """Test connected==True."""
        assert self.connection.connection_status.is_connected

    @pytest.mark.asyncio
    async def test_disconnected(self):
        """Test disconnect."""
        assert self.connection.connection_status.is_connected
        with patch.object(
            self.connection.channel,
            "_request_text",
            make_async("<response><message>Goodbye!</message></response>"),
        ):
            await self.connection.disconnect()
        assert not self.connection.connection_status.is_connected

    @pytest.mark.asyncio
    async def test_register_service(self):
        """Test register service."""
        agent_location = Location(52.2057092, 2.1183431)
        service_instance = {"location": agent_location}
        service_description = Description(
            service_instance, data_model=models.AGENT_LOCATION_MODEL
        )
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.REGISTER_SERVICE,
            dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
            service_description=service_description,
        )
        message.counterparty = SOEFConnection.connection_id.latest
        sending_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue is not None
        envelope = Envelope(
            to=message.counterparty,
            sender=self.crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )

        with patch.object(
            self.connection.channel,
            "_request_text",
            make_async(self.generic_success_response),
        ):
            await self.connection.send(envelope)

        with pytest.raises(asyncio.TimeoutError):  # got no message back
            await asyncio.wait_for(self.connection.receive(), timeout=1)

        assert self.connection.channel.agent_location == agent_location

    @pytest.mark.asyncio
    async def test_bad_register_service(self):
        """Test register service fails on bad values provided."""
        bad_location_model = DataModel(
            "not_location_agent",
            [
                Attribute(
                    "non_location", Location, True, "The location where the agent is."
                )
            ],
            "A data model to describe location of an agent.",
        )
        agent_location = Location(52.2057092, 2.1183431)
        service_instance = {"non_location": agent_location}
        service_description = Description(
            service_instance, data_model=bad_location_model
        )
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.REGISTER_SERVICE,
            dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
            service_description=service_description,
        )
        message.counterparty = SOEFConnection.connection_id.latest
        sending_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue is not None
        envelope = Envelope(
            to=message.counterparty,
            sender=self.crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )
        await self.connection.send(envelope)

        expected_envelope = await asyncio.wait_for(self.connection.receive(), timeout=1)
        assert expected_envelope
        assert (
            expected_envelope.message.performative
            == OefSearchMessage.Performative.OEF_ERROR
        )
        message = copy.deepcopy(expected_envelope.message)
        message.is_incoming = True  # TODO: fix
        message.counterparty = SOEFConnection.connection_id.latest  # TODO; fix
        receiving_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue == receiving_dialogue

    @pytest.mark.asyncio
    async def test_unregister_service(self):
        """Test unregister service."""
        agent_location = Location(52.2057092, 2.1183431)
        service_instance = {"location": agent_location}
        service_description = Description(
            service_instance, data_model=models.AGENT_LOCATION_MODEL
        )
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.UNREGISTER_SERVICE,
            dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
            service_description=service_description,
        )
        message.counterparty = SOEFConnection.connection_id.latest
        sending_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue is not None
        envelope = Envelope(
            to=message.counterparty,
            sender=self.crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )
        with patch.object(
            self.connection.channel,
            "_request_text",
            make_async("<response><message>Goodbye!</message></response>"),
        ):
            await self.connection.send(envelope)

        assert self.connection.channel.unique_page_address is None

    @pytest.mark.asyncio
    async def test_register_personailty_pieces(self):
        """Test register service with personality pieces."""
        service_instance = {"piece": "genus", "value": "service"}
        service_description = Description(
            service_instance, data_model=models.AGENT_PERSONALITY_MODEL
        )
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.REGISTER_SERVICE,
            dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
            service_description=service_description,
        )
        message.counterparty = SOEFConnection.connection_id.latest
        sending_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue is not None
        envelope = Envelope(
            to=message.counterparty,
            sender=self.crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )
        with patch.object(
            self.connection.channel,
            "_request_text",
            make_async(self.generic_success_response),
        ):
            await self.connection.send(envelope)

        with pytest.raises(asyncio.TimeoutError):  # got no message back
            await asyncio.wait_for(self.connection.receive(), timeout=1)

    @pytest.mark.asyncio
    async def test_send_excluded_protocol(self, caplog):
        """Test fail on unsupported protocol."""
        envelope = Envelope(
            to="soef",
            sender=self.crypto.address,
            protocol_id=UNKNOWN_PROTOCOL_PUBLIC_ID,
            message=b"some msg",
        )
        self.connection.channel.excluded_protocols = [UNKNOWN_PROTOCOL_PUBLIC_ID]
        with pytest.raises(
            ValueError, match=r"Cannot send message, invalid protocol:.*"
        ):
            await self.connection.send(envelope)

    @pytest.mark.asyncio
    async def test_bad_message(self, caplog):
        """Test fail on bad message."""
        envelope = Envelope(
            to="soef",
            sender=self.crypto.address,
            protocol_id=UNKNOWN_PROTOCOL_PUBLIC_ID,
            message=b"some msg",
        )
        with pytest.raises(ValueError):
            await self.connection.send(envelope)

    @pytest.mark.asyncio
    async def test_bad_performative(self, caplog):
        """Test fail on bad perfromative."""
        agent_location = Location(52.2057092, 2.1183431)
        service_instance = {"location": agent_location}
        service_description = Description(
            service_instance, data_model=models.AGENT_LOCATION_MODEL
        )
        message = OefSearchMessage(
            performative="oef_error", service_description=service_description,
        )
        envelope = Envelope(
            to="soef",
            sender=self.crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )
        with pytest.raises(ValueError):
            await self.connection.send(envelope)

    @pytest.mark.asyncio
    async def test_bad_search_query(self, caplog):
        """Test fail on invalid query for search."""
        await self.test_register_service()
        closeness_query = Query([], model=models.AGENT_LOCATION_MODEL)
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.SEARCH_SERVICES,
            dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
            query=closeness_query,
        )
        message.counterparty = SOEFConnection.connection_id.latest
        sending_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue is not None
        envelope = Envelope(
            to=message.counterparty,
            sender=self.crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )

        with patch.object(
            self.connection.channel,
            "_request_text",
            make_async(self.search_empty_response),
        ):
            await self.connection.send(envelope)

        expected_envelope = await asyncio.wait_for(self.connection.receive(), timeout=1)
        assert expected_envelope
        message = expected_envelope.message
        assert message.performative == OefSearchMessage.Performative.OEF_ERROR
        message = copy.deepcopy(expected_envelope.message)
        message.is_incoming = True  # TODO: fix
        message.counterparty = SOEFConnection.connection_id.latest  # TODO; fix
        receiving_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue == receiving_dialogue

    @pytest.mark.asyncio
    async def test_search(self):
        """Test search."""
        agent_location = Location(52.2057092, 2.1183431)
        radius = 0.1
        close_to_my_service = Constraint(
            "location", ConstraintType("distance", (agent_location, radius))
        )
        personality_filters = [
            Constraint("genus", ConstraintType("==", "vehicle")),
            Constraint(
                "classification", ConstraintType("==", "mobility.railway.train")
            ),
        ]
        service_key_filters = [
            Constraint("custom_key", ConstraintType("==", "custom_value")),
        ]
        closeness_query = Query(
            [close_to_my_service] + personality_filters + service_key_filters
        )
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.SEARCH_SERVICES,
            dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
            query=closeness_query,
        )
        message.counterparty = SOEFConnection.connection_id.latest
        sending_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue is not None
        envelope = Envelope(
            to=message.counterparty,
            sender=self.crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )

        with patch.object(
            self.connection.channel,
            "_request_text",
            make_async(self.search_success_response),
        ):
            await self.connection.send(envelope)

        expected_envelope = await asyncio.wait_for(self.connection.receive(), timeout=1)
        assert expected_envelope
        message = expected_envelope.message
        assert len(message.agents) >= 1
        message = copy.deepcopy(expected_envelope.message)
        message.is_incoming = True  # TODO: fix
        message.counterparty = SOEFConnection.connection_id.latest  # TODO; fix
        receiving_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue == receiving_dialogue

    @pytest.mark.asyncio
    async def test_find_around_me(self):
        """Test internal method find around me."""
        agent_location = Location(52.2057092, 2.1183431)
        radius = 0.1
        close_to_my_service = Constraint(
            "location", ConstraintType("distance", (agent_location, radius))
        )
        personality_filters = [
            Constraint("genus", ConstraintType("==", "vehicle")),
            Constraint(
                "classification", ConstraintType("==", "mobility.railway.train")
            ),
        ]
        service_key_filters = [
            Constraint("custom_key", ConstraintType("==", "custom_value")),
        ]
        closeness_query = Query(
            [close_to_my_service] + personality_filters + service_key_filters
        )
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.SEARCH_SERVICES,
            dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
            query=closeness_query,
        )
        message.counterparty = SOEFConnection.connection_id.latest
        sending_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue is not None
        with patch.object(
            self.connection.channel,
            "_request_text",
            new_callable=MagicMock,
            side_effect=[
                wrap_future(self.search_empty_response),
                wrap_future(self.search_success_response),
                wrap_future(self.search_fail_response),
            ],
        ):
            await self.connection.channel._find_around_me(
                message, sending_dialogue, 1, {}
            )
            await self.connection.channel._find_around_me(
                message, sending_dialogue, 1, {}
            )
            with pytest.raises(SOEFException, match=r"`find_around_me` error: .*"):
                await self.connection.channel._find_around_me(
                    message, sending_dialogue, 1, {}
                )

    @pytest.mark.asyncio
    async def test_register_agent(self):
        """Test internal method register agent."""
        resp_text = '<?xml version="1.0" encoding="UTF-8"?><response></response>'
        with patch.object(
            self.connection.channel, "_request_text", make_async(resp_text)
        ):
            with pytest.raises(
                SOEFException,
                match="Agent registration error - page address or token not received",
            ):
                await self.connection.channel._register_agent()

        resp_text = '<?xml version="1.0" encoding="UTF-8"?><response><encrypted>0</encrypted><token>672DB3B67780F98984ABF1123BD11</token><page_address>oef_C95B21A4D5759C8FE7A6304B62B726AB8077BEE4BA191A7B92B388F9B1</page_address></response>'
        with patch.object(
            self.connection.channel, "_request_text", make_async(resp_text)
        ):
            with pytest.raises(
                SOEFException, match=r"`acknowledge` error: .*",
            ):
                await self.connection.channel._register_agent()

        resp_text1 = '<?xml version="1.0" encoding="UTF-8"?><response><encrypted>0</encrypted><token>672DB3B67780F98984ABF1123BD11</token><page_address>oef_C95B21A4D5759C8FE7A6304B62B726AB8077BEE4BA191A7B92B388F9B1</page_address></response>'
        resp_text2 = '<?xml version="1.0" encoding="UTF-8"?><response><success>1</success></response>'
        resp_text3 = '<?xml version="1.0" encoding="UTF-8"?><response><success>1</success></response>'
        with patch.object(
            self.connection.channel,
            "_request_text",
            new_callable=MagicMock,
            side_effect=[
                wrap_future(resp_text1),
                wrap_future(resp_text2),
                wrap_future(resp_text3),
            ],
        ):
            await self.connection.channel._register_agent()
            assert self.connection.channel._ping_periodic_task is not None

    @pytest.mark.asyncio
    async def test_request(self):
        """Test internal method request_text."""
        with patch("requests.request"):
            await self.connection.channel._request_text("get", "http://not-exists.com")

    @pytest.mark.asyncio
    async def test_set_location(self):
        """Test internal method set location."""
        agent_location = Location(52.2057092, 2.1183431)
        resp_text = '<?xml version="1.0" encoding="UTF-8"?><response></response>'
        with patch.object(
            self.connection.channel, "_request_text", make_async(resp_text)
        ):
            with pytest.raises(SOEFException, match=r"`set_position` error: .*"):
                await self.connection.channel._set_location(agent_location)

        resp_text = '<?xml version="1.0" encoding="UTF-8"?><response><success>1</success></response>'
        with patch.object(
            self.connection.channel, "_request_text", make_async(resp_text)
        ):
            await self.connection.channel._set_location(agent_location)

    @pytest.mark.asyncio
    async def test_set_personality_piece(self):
        """Test internal method set_personality_piece."""
        resp_text = '<?xml version="1.0" encoding="UTF-8"?><response></response>'
        with patch.object(
            self.connection.channel, "_request_text", make_async(resp_text)
        ):
            with pytest.raises(
                SOEFException, match=r"`set_personality_piece` error: .*"
            ):
                await self.connection.channel._set_personality_piece(1, 1)

        resp_text = '<?xml version="1.0" encoding="UTF-8"?><response><success>1</success></response>'
        with patch.object(
            self.connection.channel, "_request_text", make_async(resp_text)
        ):
            await self.connection.channel._set_personality_piece(1, 1)

    def teardown(self):
        """Clean up."""
        try:
            with patch.object(
                self.connection.channel,
                "_request_text",
                make_async("<response><message>Goodbye!</message></response>"),
            ):
                self.loop.run_until_complete(self.connection.disconnect())
        except Exception:  # nosec
            pass

    @pytest.mark.asyncio
    async def test__set_value(self):
        """Test set pieces."""
        resp_text = '<?xml version="1.0" encoding="UTF-8"?><response></response>'
        with patch.object(
            self.connection.channel, "_request_text", make_async(resp_text)
        ):
            with pytest.raises(SOEFException, match=r"`set_personality_piece` error:"):
                await self.connection.channel._set_personality_piece(1, 1)

        resp_text = '<?xml version="1.0" encoding="UTF-8"?><response><success>1</success></response>'
        with patch.object(
            self.connection.channel, "_request_text", make_async(resp_text)
        ):
            await self.connection.channel._set_personality_piece(1, 1)

    def test_chain_identifier_fail(self):
        """Test fail on invalid chain id."""
        chain_identifier = "test"
        identity = Identity("", "")

        configuration = ConnectionConfig(
            api_key="TwiCIriSl0mLahw17pyqoA",
            soef_addr="soef.fetch.ai",
            soef_port=9002,
            restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
            connection_id=SOEFConnection.connection_id,
            chain_identifier=chain_identifier,
        )
        with pytest.raises(ValueError, match="Unsupported chain_identifier"):
            SOEFConnection(
                configuration=configuration, identity=identity,
            )

    def test_chain_identifier_ok(self):
        """Test set valid chain id."""
        chain_identifier = "fetchai_cosmos"
        identity = Identity("", "")

        configuration = ConnectionConfig(
            api_key="TwiCIriSl0mLahw17pyqoA",
            soef_addr="soef.fetch.ai",
            soef_port=9002,
            restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
            connection_id=SOEFConnection.connection_id,
            chain_identifier=chain_identifier,
        )
        connection = SOEFConnection(configuration=configuration, identity=identity,)

        assert connection.channel.chain_identifier == chain_identifier

    @pytest.mark.asyncio
    async def test_ping_command(self):
        """Test set service key."""
        service_description = Description({}, data_model=models.PING_MODEL)
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.REGISTER_SERVICE,
            dialogue_reference=self.oef_search_dialogues.new_self_initiated_dialogue_reference(),
            service_description=service_description,
        )
        message.counterparty = SOEFConnection.connection_id.latest
        sending_dialogue = self.oef_search_dialogues.update(message)
        assert sending_dialogue is not None
        envelope = Envelope(
            to=message.counterparty,
            sender=self.crypto.address,
            protocol_id=message.protocol_id,
            message=message,
        )

        with patch.object(
            self.connection.channel,
            "_request_text",
            make_async(self.generic_success_response),
        ):
            await self.connection.send(envelope)

        with pytest.raises(asyncio.TimeoutError):  # got no message back
            await asyncio.wait_for(self.connection.receive(), timeout=1)

    @pytest.mark.asyncio
    async def test_periodic_ping_task_is_set(self):
        """Test periodic ping task is set on agent register."""
        resp_text1 = '<?xml version="1.0" encoding="UTF-8"?><response><encrypted>0</encrypted><token>672DB3B67780F98984ABF1123BD11</token><page_address>oef_C95B21A4D5759C8FE7A6304B62B726AB8077BEE4BA191A7B92B388F9B1</page_address></response>'
        resp_text2 = '<?xml version="1.0" encoding="UTF-8"?><response><success>1</success></response>'
        resp_text3 = '<?xml version="1.0" encoding="UTF-8"?><response><success>1</success></response>'
        self.connection.channel.PING_PERIOD = 0.1

        with patch.object(
            self.connection.channel,
            "_request_text",
            new_callable=MagicMock,
            side_effect=[
                wrap_future(resp_text1),
                wrap_future(resp_text2),
                wrap_future(resp_text3),
            ],
        ):
            with patch.object(self.connection.channel, "_ping_command",) as mocked_ping:
                await self.connection.channel._register_agent()

                assert self.connection.channel._ping_periodic_task is not None
                await asyncio.sleep(0.3)
                assert mocked_ping.call_count > 1
示例#11
0
def test_soef():

    # First run OEF in a separate terminal: python scripts/oef/launch.py -c ./scripts/oef/launch_config.json
    crypto = FetchAICrypto()

    # create the connection and multiplexer objects
    soef_connection = SOEFConnection(
        api_key="TwiCIriSl0mLahw17pyqoA",
        soef_addr="soef.fetch.ai",
        soef_port=9002,
        address=crypto.address,
    )
    multiplexer = Multiplexer([soef_connection])
    try:
        # Set the multiplexer running in a different thread
        t = Thread(target=multiplexer.connect)
        t.start()

        time.sleep(3.0)

        # register a service with location
        attr_service_name = Attribute("service_name", str, True,
                                      "The name of the service.")
        attr_location = Attribute(
            "location", Location, True,
            "The location where the service is provided.")
        service_location_model = DataModel(
            "location_service",
            [attr_service_name, attr_location],
            "A data model to describe location of a service.",
        )
        service_name = "train"
        service_location = Location(52.2057092, 2.1183431)
        service_instance = {
            "service_name": service_name,
            "location": service_location
        }
        service_description = Description(service_instance,
                                          data_model=service_location_model)
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.REGISTER_SERVICE,
            service_description=service_description,
        )
        message_b = OefSearchSerializer().encode(message)
        envelope = Envelope(
            to="soef",
            sender=crypto.address,
            protocol_id=ProtocolId.from_str("fetchai/oef_search:0.1.0"),
            message=message_b,
        )
        logger.info(
            "Registering service={} at location=({},{}) by agent={}".format(
                service_name,
                service_location.latitude,
                service_location.longitude,
                crypto.address,
            ))
        multiplexer.put(envelope)

        # find agents near the previously registered service
        radius = 0.1
        matches_my_service_name = Constraint(
            "service_name", ConstraintType("==", service_name))
        close_to_my_service = Constraint(
            "location", ConstraintType("distance", (service_location, radius)))
        closeness_query = Query([matches_my_service_name, close_to_my_service],
                                model=service_location_model)
        message = OefSearchMessage(
            performative=OefSearchMessage.Performative.SEARCH_SERVICES,
            query=closeness_query,
        )
        message_b = OefSearchSerializer().encode(message)
        envelope = Envelope(
            to="soef",
            sender=crypto.address,
            protocol_id=ProtocolId.from_str("fetchai/oef_search:0.1.0"),
            message=message_b,
        )
        logger.info(
            "Searching for agents in radius={} of service={} at location=({},{})"
            .format(
                radius,
                service_name,
                service_location.latitude,
                service_location.longitude,
            ))
        multiplexer.put(envelope)
        time.sleep(4.0)

        # check for search results
        envelope = multiplexer.get()
        message = OefSearchSerializer().decode(envelope.message)
        assert len(message.agents) >= 0

    finally:
        # Shut down the multiplexer
        multiplexer.disconnect()
        t.join()
示例#12
0
def run():
    # Create a private key
    create_private_key(CosmosCrypto.identifier)

    # Set up the wallet, identity and (empty) resources
    wallet = Wallet(
        private_key_paths={CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE},
        connection_private_key_paths={CosmosCrypto.identifier: COSMOS_PRIVATE_KEY_FILE},
    )
    identity = Identity("my_aea", address=wallet.addresses.get(CosmosCrypto.identifier))
    resources = Resources()

    # specify the default routing for some protocols
    default_routing = {
        PublicId.from_str("fetchai/ledger_api:0.1.0"): LedgerConnection.connection_id,
        PublicId.from_str("fetchai/oef_search:0.3.0"): SOEFConnection.connection_id,
    }
    default_connection = SOEFConnection.connection_id

    # create the AEA
    my_aea = AEA(
        identity,
        wallet,
        resources,
        default_connection=default_connection,
        default_routing=default_routing,
    )

    # Add the default protocol (which is part of the AEA distribution)
    default_protocol = Protocol.from_dir(os.path.join(AEA_DIR, "protocols", "default"))
    resources.add_protocol(default_protocol)

    # Add the signing protocol (which is part of the AEA distribution)
    signing_protocol = Protocol.from_dir(os.path.join(AEA_DIR, "protocols", "signing"))
    resources.add_protocol(signing_protocol)

    # Add the ledger_api protocol
    ledger_api_protocol = Protocol.from_dir(
        os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "ledger_api",)
    )
    resources.add_protocol(ledger_api_protocol)

    # Add the oef_search protocol
    oef_protocol = Protocol.from_dir(
        os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "oef_search",)
    )
    resources.add_protocol(oef_protocol)

    # Add the fipa protocol
    fipa_protocol = Protocol.from_dir(
        os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "fipa",)
    )
    resources.add_protocol(fipa_protocol)

    # Add the LedgerAPI connection
    configuration = ConnectionConfig(connection_id=LedgerConnection.connection_id)
    ledger_api_connection = LedgerConnection(
        configuration=configuration, identity=identity
    )
    resources.add_connection(ledger_api_connection)

    # Add the P2P connection
    configuration = ConnectionConfig(
        connection_id=P2PLibp2pConnection.connection_id,
        delegate_uri="127.0.0.1:11001",
        entry_peers=[ENTRY_PEER_ADDRESS],
        local_uri="127.0.0.1:9001",
        log_file="libp2p_node.log",
        public_uri="127.0.0.1:9001",
    )
    p2p_connection = P2PLibp2pConnection(
        configuration=configuration,
        identity=identity,
        crypto_store=wallet.connection_cryptos,
    )
    resources.add_connection(p2p_connection)

    # Add the SOEF connection
    configuration = ConnectionConfig(
        api_key=API_KEY,
        soef_addr=SOEF_ADDR,
        soef_port=SOEF_PORT,
        restricted_to_protocols={PublicId.from_str("fetchai/oef_search:0.3.0")},
        connection_id=SOEFConnection.connection_id,
        delegate_uri="127.0.0.1:11001",
        entry_peers=[ENTRY_PEER_ADDRESS],
        local_uri="127.0.0.1:9001",
        log_file="libp2p_node.log",
        public_uri="127.0.0.1:9001",
    )
    soef_connection = SOEFConnection(configuration=configuration, identity=identity)
    resources.add_connection(soef_connection)

    # Add the error and weather_client skills
    error_skill = Skill.from_dir(
        os.path.join(AEA_DIR, "skills", "error"), agent_context=my_aea.context
    )
    weather_skill = Skill.from_dir(
        os.path.join(ROOT_DIR, "packages", "fetchai", "skills", "weather_client"),
        agent_context=my_aea.context,
    )

    strategy = cast(Strategy, weather_skill.models.get("strategy"))
    strategy._is_ledger_tx = False

    for skill in [error_skill, weather_skill]:
        resources.add_skill(skill)

    # Run the AEA
    try:
        logger.info("STARTING AEA NOW!")
        my_aea.start()
    except KeyboardInterrupt:
        logger.info("STOPPING AEA NOW!")
        my_aea.stop()
示例#13
0
def run():
    """Run demo."""

    # Create a private key
    create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE)
    create_private_key(FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE_CONNECTION)

    # Set up the wallet, identity and (empty) resources
    wallet = Wallet(
        private_key_paths={FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE},
        connection_private_key_paths={
            FetchAICrypto.identifier: FETCHAI_PRIVATE_KEY_FILE_CONNECTION
        },
    )
    identity = Identity(
        "my_aea", address=wallet.addresses.get(FetchAICrypto.identifier)
    )
    resources = Resources()
    data_dir = os.getcwd()

    # specify the default routing for some protocols
    default_routing = {
        LedgerApiMessage.protocol_id: LedgerConnection.connection_id,
        OefSearchMessage.protocol_id: SOEFConnection.connection_id,
    }
    default_connection = P2PLibp2pConnection.connection_id

    state_update_protocol = Protocol.from_dir(
        os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "state_update")
    )
    resources.add_protocol(state_update_protocol)

    # Add the default protocol (which is part of the AEA distribution)
    default_protocol = Protocol.from_dir(
        os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "default")
    )
    resources.add_protocol(default_protocol)

    # Add the signing protocol (which is part of the AEA distribution)
    signing_protocol = Protocol.from_dir(
        os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "signing")
    )
    resources.add_protocol(signing_protocol)

    # Add the ledger_api protocol
    ledger_api_protocol = Protocol.from_dir(
        os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "ledger_api",)
    )
    resources.add_protocol(ledger_api_protocol)

    # Add the oef_search protocol
    oef_protocol = Protocol.from_dir(
        os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "oef_search",)
    )
    resources.add_protocol(oef_protocol)

    # Add the fipa protocol
    fipa_protocol = Protocol.from_dir(
        os.path.join(os.getcwd(), "packages", "fetchai", "protocols", "fipa",)
    )
    resources.add_protocol(fipa_protocol)

    # Add the LedgerAPI connection
    configuration = ConnectionConfig(connection_id=LedgerConnection.connection_id)
    ledger_api_connection = LedgerConnection(
        configuration=configuration, data_dir=data_dir, identity=identity
    )
    resources.add_connection(ledger_api_connection)

    # Add the P2P connection
    cert_path = ".certs/conn_cert.txt"
    cert_request = CertRequest(
        identifier="acn",
        ledger_id=FetchAICrypto.identifier,
        not_after="2022-01-01",
        not_before="2021-01-01",
        public_key="fetchai",
        save_path=cert_path,
    )
    public_key = wallet.connection_cryptos.public_keys.get(FetchAICrypto.identifier)
    message = cert_request.get_message(public_key)
    make_certificate(
        FetchAICrypto.identifier, FETCHAI_PRIVATE_KEY_FILE, message, cert_path
    )
    configuration = ConnectionConfig(
        connection_id=P2PLibp2pConnection.connection_id,
        delegate_uri="127.0.0.1:11001",
        entry_peers=[ENTRY_PEER_ADDRESS],
        local_uri="127.0.0.1:9001",
        log_file="libp2p_node.log",
        public_uri="127.0.0.1:9001",
        build_directory=os.getcwd(),
        build_entrypoint="check_dependencies.py",
        cert_requests=[cert_request],
    )
    configuration.directory = os.path.dirname(
        packages.fetchai.connections.p2p_libp2p.connection.__file__
    )

    AEABuilder.run_build_for_component_configuration(configuration)

    p2p_connection = P2PLibp2pConnection(
        configuration=configuration,
        data_dir=data_dir,
        identity=identity,
        crypto_store=wallet.connection_cryptos,
    )
    resources.add_connection(p2p_connection)

    # Add the SOEF connection
    configuration = ConnectionConfig(
        api_key=API_KEY,
        soef_addr=SOEF_ADDR,
        soef_port=SOEF_PORT,
        restricted_to_protocols={OefSearchMessage.protocol_id},
        connection_id=SOEFConnection.connection_id,
    )
    soef_connection = SOEFConnection(
        configuration=configuration, data_dir=data_dir, identity=identity
    )
    resources.add_connection(soef_connection)

    # create the AEA
    my_aea = AEA(
        identity,
        wallet,
        resources,
        data_dir,
        default_connection=default_connection,
        default_routing=default_routing,
    )
    # Add the error and weather_client skills
    error_skill = Skill.from_dir(
        os.path.join(ROOT_DIR, "packages", "fetchai", "skills", "error"),
        agent_context=my_aea.context,
    )
    weather_skill = Skill.from_dir(
        os.path.join(ROOT_DIR, "packages", "fetchai", "skills", "weather_client"),
        agent_context=my_aea.context,
    )

    strategy = cast(Strategy, weather_skill.models.get("strategy"))
    strategy._is_ledger_tx = False

    for skill in [error_skill, weather_skill]:
        resources.add_skill(skill)

    # Run the AEA
    try:
        logger.info("STARTING AEA NOW!")
        my_aea.start()
    except KeyboardInterrupt:
        logger.info("STOPPING AEA NOW!")
        my_aea.stop()