async def test_agents_can_talk_both_ways(alice, bob): logger = logging.getLogger(__name__) await connect_alice_and_bob(alice, bob) alice.triggered = asyncio.Event() bob.triggered = asyncio.Event() @alice.route('test/protocol/1.0/test') async def alice_msg_handle(msg, alice): logger.debug('Alice got: %s', msg) alice.triggered.set() @bob.route('test/protocol/1.0/test') async def bob_msg_handle(msg, bob): logger.debug('Bob got: %s', msg) bob.triggered.set() logger.debug('Packing message to Alice: %s, %s', alice.did, alice.vk) await bob.send( Message({'@type': 'test/protocol/1.0/test'}), alice.vk, to_did=alice.did, ) await alice.send( Message({'@type': 'test/protocol/1.0/test'}), bob.vk, to_did=bob.did, ) await asyncio.wait_for(alice.triggered.wait(), 1) assert alice.triggered.is_set() await asyncio.wait_for(bob.triggered.wait(), 1) assert bob.triggered.is_set()
async def test_simple_messaging(config, agent): """ Show simple messages being passed to and from tested agent """ _my_did, my_vk, their_did, their_vk = \ await static_connection(agent, config['static_connection']) expected_schema = MessageSchema({ '@type': 'test/protocol/1.0/test', '@id': str, 'msg': 'pong' }) ping = Message({'@type': 'test/protocol/1.0/test', 'msg': 'ping'}) print('Sending message:', ping.pretty_print()) await agent.send(ping, their_vk, to_did=their_did, from_vk=my_vk) pong = await agent.expect_message('test/protocol/1.0/test', 1) print('Received message:', pong.pretty_print()) assert pong.mtc[CONFIDENTIALITY | INTEGRITY | AUTHENTICATED_ORIGIN | DESERIALIZE_OK] assert not pong.mtc[NONREPUDIATION] assert pong.mtc.ad['sender_vk'] == their_vk assert pong.mtc.ad['recip_vk'] == my_vk assert expected_schema.validate(pong) assert agent.ok()
async def test_module_routing_many(): """ Test that routing to a module works. """ dispatcher = Dispatcher() dispatcher.called_module = None routed_event = asyncio.Event() class TestModule1(Module): DOC_URI = '' PROTOCOL = 'test_protocol' VERSION = '1.0' async def testing_type(self, msg, *args, **kwargs): kwargs['dispatcher'].called_module = 1 kwargs['event'].set() class TestModule2(Module): DOC_URI = '' PROTOCOL = 'test_protocol' VERSION = '2.0' async def testing_type(self, msg, *args, **kwargs): kwargs['dispatcher'].called_module = 2 kwargs['event'].set() dispatcher.route_module(TestModule1()) dispatcher.route_module(TestModule2()) test_msg = Message({ '@type': 'test_protocol/1.0/testing_type', 'test': 'test' }) await dispatcher.dispatch(test_msg, event=routed_event, dispatcher=dispatcher) await routed_event.wait() assert routed_event.is_set() assert dispatcher.called_module == 1 routed_event.clear() test_msg = Message({ '@type': 'test_protocol/2.0/testing_type', 'test': 'test' }) await dispatcher.dispatch(test_msg, event=routed_event, dispatcher=dispatcher) await routed_event.wait() assert routed_event.is_set() assert dispatcher.called_module == 2
def build_invite(label: str, connection_key: str, endpoint: str) -> str: msg = Message({ '@type': INVITE, 'label': label, 'recipientKeys': [connection_key], 'serviceEndpoint': endpoint, 'routingKeys': [] }) b64_invite = base64.urlsafe_b64encode(bytes(msg.serialize(), 'utf-8')).decode('ascii') return '{}?c_i={}'.format(endpoint, b64_invite)
async def test_module_routing_explicit_def(): """ Test that routing to a module works. """ dispatcher = Dispatcher() called_event = asyncio.Event() class TestModule(Module): DOC_URI = '' PROTOCOL = 'test_protocol' VERSION = '1.0' routes = {} @route_def(routes, 'test_protocol/1.0/testing_type') async def route_gets_called(self, msg, **kwargs): kwargs['event'].set() mod = TestModule() dispatcher.route_module(mod) test_msg = Message({ '@type': 'test_protocol/1.0/testing_type', 'test': 'test' }) await dispatcher.dispatch(test_msg, event=called_event) assert called_event.is_set()
def build_request(label: str, my_did: str, my_vk: str, endpoint: str) -> Message: """ Construct a connection request. """ return Message({ '@type': REQUEST, '@id': str(uuid.uuid4()), 'label': label, 'connection': { 'DID': my_did, 'DIDDoc': { "@context": "https://w3id.org/did/v1", "id": my_did, "publicKey": [{ "id": my_did + "#keys-1", "type": "Ed25519VerificationKey2018", "controller": my_did, "publicKeyBase58": my_vk }], "service": [{ "id": my_did + ";indy", "type": "IndyAgent", "recipientKeys": [my_vk], "routingKeys": [], "serviceEndpoint": endpoint, }], } } })
def build_response(req_id: str, my_did: str, my_vk: str, endpoint: str) -> Message: return Message({ '@type': RESPONSE, '@id': str(uuid.uuid4()), '~thread': { 'thid': req_id, 'sender_order': 0 }, 'connection': { 'DID': my_did, 'DIDDoc': { "@context": "https://w3id.org/did/v1", "id": my_did, "publicKey": [{ "id": my_did + "#keys-1", "type": "Ed25519VerificationKey2018", "controller": my_did, "publicKeyBase58": my_vk }], "service": [{ "id": my_did + ";indy", "type": "IndyAgent", "recipientKeys": [my_vk], "routingKeys": [], "serviceEndpoint": endpoint, }], } } })
async def packed_message_anonymous(wallet_handle, loopback_relationship): """ Get a packed message """ _, a_vk = loopback_relationship yield await crypto.pack_message( wallet_handle, Message({'@type': 'test/protocol/1.0/test'}).serialize(), [a_vk] )
def parse_invite(invite_url: str) -> Message: """ Parse an invite url """ matches = re.match('(.+)?c_i=(.+)', invite_url) assert matches, 'Improperly formatted invite url!' invite_msg = Message.deserialize( base64.urlsafe_b64decode(matches.group(2)).decode('ascii')) INVITE_SCHEMA.validate(invite_msg) return invite_msg
def test_valid_message_no_doc_uri(): """ Test basic message creation and member access. """ id_ = '12345' msg = Message({'@type': TEST_TYPE_NO_DOC, '@id': id_}) assert msg.type == TEST_TYPE_NO_DOC assert msg.id == id_ assert msg.doc_uri == '' assert msg.protocol == 'protocol' assert msg.version == '1.0' assert msg.short_type == 'test' assert msg.version_info == Semver(1, 0, 0)
def test_message_serialization(): """ Test deserializing and serializing a message """ msg = Message.deserialize('{"@type": "%s"}' % TEST_TYPE) assert msg.type == TEST_TYPE assert msg.id is not None assert msg.doc_uri == 'test_type/' assert msg.protocol == 'protocol' assert msg.version == '1.0' assert msg.short_type == 'test' assert msg.version_info == Semver(1, 0, 0) assert msg.serialize() == \ '{"@type": "%s", "@id": "%s"}' % (TEST_TYPE, msg.id)
async def test_send(conductor, loopback_relationship): """ Test that conductor can send a message """ a_did, a_vk = loopback_relationship send_task = create_task(conductor.send( Message({'@type': 'test/protocol/1.0/test'}), a_vk, to_did=a_did, from_key=a_vk )) conn = await conductor.connection_queue.get() await conductor.message_reader(conn) msg = await asyncio.wait_for(conductor.recv(), 5) assert msg.type == 'test/protocol/1.0/test' send_task.cancel()
async def test_unpack_plaintext(conductor): """ Test unpack behavior for plaintext """ msg = await conductor.unpack( Message({'@type': 'test/protocol/1.0/test'}).serialize() ) assert msg.mtc[DESERIALIZE_OK] assert not msg.mtc[ AUTHENTICATED_ORIGIN | CONFIDENTIALITY | INTEGRITY | LIMITED_SCOPE | NONREPUDIATION ]
async def test_agents_can_talk(alice, bob): logger = logging.getLogger(__name__) await connect_alice_and_bob(alice, bob) alice.triggered = asyncio.Event() @alice.route('test/protocol/1.0/test') async def alice_msg_handle(msg, alice): alice.triggered.set() await bob.send(Message({'@type': 'test/protocol/1.0/test'}), alice.vk, to_did=alice.did) assert alice.triggered.is_set()
async def test_module_routing_no_matching_version(): """ Test that routing to a module works. """ dispatcher = Dispatcher() called_event = asyncio.Event() class TestModule(Module): DOC_URI = '' PROTOCOL = 'test_protocol' VERSION = '1.0' async def testing_type(self, msg, *args, **kwargs): kwargs['event'].set() mod = TestModule() dispatcher.route_module(mod) test_msg = Message({ '@type': 'test_protocol/3.0/testing_type', 'test': 'test' }) with pytest.raises(NoRegisteredRouteException): await dispatcher.dispatch(test_msg, event=called_event)
async def test_module_routing_minor_version_different(): """ Test that routing to a module works. """ dispatcher = Dispatcher() called_event = asyncio.Event() class TestModule(Module): DOC_URI = '' PROTOCOL = 'test_protocol' VERSION = '1.4' async def testing_type(self, msg, *args, **kwargs): kwargs['event'].set() mod = TestModule() dispatcher.route_module(mod) test_msg = Message({ '@type': 'test_protocol/1.0/testing_type', 'test': 'test' }) await dispatcher.dispatch(test_msg, event=called_event) assert called_event.is_set()
def validate(self, msg: Message): """ Validate message, storing defaults inserted by validation. """ msg.update(self._schema.validate(dict(msg))) return msg
def test_bad_message_type(type_str): """ Test bad message types raise InvalidMessage """ with pytest.raises(InvalidMessage): Message({'@type': type_str})
def test_bad_message_id(id_): """ Test message with bad message id """ with pytest.raises(InvalidMessage): Message({'@type': TEST_TYPE, '@id': id_})
def test_id_generated(): """ Test ID is generated for message where one is not specified. """ msg = Message({'@type': TEST_TYPE}) assert msg.type == TEST_TYPE assert msg.id is not None