Exemple #1
0
    def test_lookup_some_pending_some_contacted(self):
        """
        Ensures the _lookup method works with some pending slots available and
        some nodes previously contacted.
        """
        lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
        # Reset in order to manually create the correct state.
        lookup.pending_requests = {}
        lookup.contacted = set()
        self.node.send_find.call_count = 0

        # Add a single pending request.
        pending_uuid = str(uuid.uuid4())
        pending_future = asyncio.Future()
        lookup.pending_requests[pending_uuid] = pending_future
        # Add a single contact to the contacted list.
        lookup.contacted.add(lookup.shortlist[0])
        # Sanity check.
        self.assertEqual(1, len(lookup.pending_requests))
        self.assertEqual(1, len(lookup.contacted))
        # Re-run _lookup and check state has been correctly updated.
        lookup._lookup()
        self.assertEqual(ALPHA - 1, self.node.send_find.call_count)
        self.assertEqual(ALPHA, len(lookup.pending_requests))
        self.assertEqual(ALPHA, len(lookup.contacted))
Exemple #2
0
    def test_lookup_some_pending_some_contacted(self):
        """
        Ensures the _lookup method works with some pending slots available and
        some nodes previously contacted.
        """
        lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
        # Reset in order to manually create the correct state.
        lookup.pending_requests = {}
        lookup.contacted = set()
        self.node.send_find.call_count = 0

        # Add a single pending request.
        pending_uuid = str(uuid.uuid4())
        pending_future = asyncio.Future()
        lookup.pending_requests[pending_uuid] = pending_future
        # Add a single contact to the contacted list.
        lookup.contacted.add(lookup.shortlist[0])
        # Sanity check.
        self.assertEqual(1, len(lookup.pending_requests))
        self.assertEqual(1, len(lookup.contacted))
        # Re-run _lookup and check state has been correctly updated.
        lookup._lookup()
        self.assertEqual(ALPHA - 1, self.node.send_find.call_count)
        self.assertEqual(ALPHA, len(lookup.pending_requests))
        self.assertEqual(ALPHA, len(lookup.contacted))
Exemple #3
0
 def test_lookup_none_pending_all_contacted(self):
     """
     Ensures the _lookup method works with no pending requests and all known
     peer nodes having been contacted.
     """
     lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
     # Put the lookup object in the state to test.
     lookup.pending_requests = {}
     for contact in lookup.shortlist:
         lookup.contacted.add(contact)
     self.node.send_find.call_count = 0
     # Re-run _lookup and test
     lookup._lookup()
     self.assertEqual(self.node.send_find.call_count, 0)
Exemple #4
0
 def test_lookup_all_pending(self):
     """
     If no more pending slots are available ensure no further network calls
     are made.
     """
     lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
     # Sanity check that ALPHA slots are full.
     self.assertEqual(self.node.send_find.call_count, ALPHA)
     self.assertEqual(len(lookup.pending_requests), ALPHA)
     self.assertEqual(len(lookup.contacted), ALPHA)
     self.assertEqual(len(lookup.shortlist), K)
     # Re-run _lookup and ensure no further network calls have been made.
     lookup._lookup()
     self.assertEqual(self.node.send_find.call_count, ALPHA)
Exemple #5
0
 def test_lookup_all_pending(self):
     """
     If no more pending slots are available ensure no further network calls
     are made.
     """
     lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
     # Sanity check that ALPHA slots are full.
     self.assertEqual(self.node.send_find.call_count, ALPHA)
     self.assertEqual(len(lookup.pending_requests), ALPHA)
     self.assertEqual(len(lookup.contacted), ALPHA)
     self.assertEqual(len(lookup.shortlist), K)
     # Re-run _lookup and ensure no further network calls have been made.
     lookup._lookup()
     self.assertEqual(self.node.send_find.call_count, ALPHA)
Exemple #6
0
 def test_lookup_none_pending_all_contacted(self):
     """
     Ensures the _lookup method works with no pending requests and all known
     peer nodes having been contacted.
     """
     lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
     # Put the lookup object in the state to test.
     lookup.pending_requests = {}
     for contact in lookup.shortlist:
         lookup.contacted.add(contact)
     self.node.send_find.call_count = 0
     # Re-run _lookup and test
     lookup._lookup()
     self.assertEqual(self.node.send_find.call_count, 0)
Exemple #7
0
 def test_handle_response_all_shortlist_contacted_value_not_found(self):
     """
     If there are no more pending requests and all the nodes in the
     shortlist have been contacted then return the shortlist of nearest
     peer nodes to the target if the lookup is a FindNode.
     """
     lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     uuids = [uuid for uuid in lookup.pending_requests.keys()]
     uuid = uuids[0]
     contact = lookup.shortlist[0]
     # Only one item in pending_requests
     for i in range(1, len(uuids)):
         del lookup.pending_requests[uuids[i]]
     self.assertEqual(1, len(lookup.pending_requests))
     # Add K items from shortlist to the contacted set.
     for contact in lookup.shortlist:
         lookup.contacted.add(contact)
     # Cause the lookup to fire.
     msg = Nodes(uuid, self.node.network_id, self.node.network_id,
                 self.reply_port, self.version, self.seal,
                 self.contacts)
     response = asyncio.Future()
     response.set_result(msg)
     lookup._handle_response(uuid, contact, response)
     # The _lookup method should not be called.
     self.assertEqual(lookup._lookup.call_count, 0)
     # The lookup task has fired.
     self.assertTrue(lookup.done())
     with self.assertRaises(ValueNotFound) as result:
         lookup.result()
     self.assertIsInstance(result.exception, ValueNotFound)
     self.assertEqual(result.exception.args[0],
                      "Unable to find value for key: {}"
                      .format(self.target))
Exemple #8
0
 def test_handle_response_all_shortlist_contacted_value_not_found(self):
     """
     If there are no more pending requests and all the nodes in the
     shortlist have been contacted then return the shortlist of nearest
     peer nodes to the target if the lookup is a FindNode.
     """
     lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     uuids = [uuid for uuid in lookup.pending_requests.keys()]
     uuid = uuids[0]
     contact = lookup.shortlist[0]
     # Only one item in pending_requests
     for i in range(1, len(uuids)):
         del lookup.pending_requests[uuids[i]]
     self.assertEqual(1, len(lookup.pending_requests))
     # Add K items from shortlist to the contacted set.
     for contact in lookup.shortlist:
         lookup.contacted.add(contact)
     # Cause the lookup to fire.
     msg = Nodes(uuid, self.node.network_id, self.node.network_id,
                 self.reply_port, self.version, self.seal,
                 self.contacts)
     response = asyncio.Future()
     response.set_result(msg)
     lookup._handle_response(uuid, contact, response)
     # The _lookup method should not be called.
     self.assertEqual(lookup._lookup.call_count, 0)
     # The lookup task has fired.
     self.assertTrue(lookup.done())
     with self.assertRaises(ValueNotFound) as result:
         lookup.result()
     self.assertIsInstance(result.exception, ValueNotFound)
     self.assertEqual(result.exception.args[0],
                      "Unable to find value for key: {}"
                      .format(self.target))
Exemple #9
0
 def test_handle_response_still_nodes_uncontacted_in_shortlist(self):
     """
     Ensure that if there are no more pending requests but there are still
     uncontacted nodes in the shortlist then restart the lookup.
     """
     lookup = Lookup(FindNode, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     uuids = [uuid for uuid in lookup.pending_requests.keys()]
     uuid = uuids[0]
     contact = lookup.shortlist[0]
     # Only one item in pending_requests
     for i in range(1, len(uuids)):
         del lookup.pending_requests[uuids[i]]
     self.assertEqual(1, len(lookup.pending_requests))
     # Add K-1 items from shortlist to the contacted set.
     for i in range(K - 1):
         lookup.contacted.add(lookup.shortlist[i])
     # Ensure lookup is called with the 20th (uncontacted) contact.
     not_contacted = lookup.shortlist[K - 1]
     self.assertNotIn(not_contacted, lookup.contacted)
     msg = Nodes(uuid, self.node.network_id, self.node.network_id,
                 self.reply_port, self.version, self.seal,
                 self.contacts)
     response = asyncio.Future()
     response.set_result(msg)
     lookup._handle_response(uuid, contact, response)
     self.assertEqual(lookup._lookup.call_count, 1)
     self.node.send_find.called_once_with(not_contacted, self.target,
                                          FindNode)
Exemple #10
0
 def test_handle_response_still_nodes_uncontacted_in_shortlist(self):
     """
     Ensure that if there are no more pending requests but there are still
     uncontacted nodes in the shortlist then restart the lookup.
     """
     lookup = Lookup(FindNode, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     uuids = [uuid for uuid in lookup.pending_requests.keys()]
     uuid = uuids[0]
     contact = lookup.shortlist[0]
     # Only one item in pending_requests
     for i in range(1, len(uuids)):
         del lookup.pending_requests[uuids[i]]
     self.assertEqual(1, len(lookup.pending_requests))
     # Add K-1 items from shortlist to the contacted set.
     for i in range(K - 1):
         lookup.contacted.add(lookup.shortlist[i])
     # Ensure lookup is called with the 20th (uncontacted) contact.
     not_contacted = lookup.shortlist[K - 1]
     self.assertNotIn(not_contacted, lookup.contacted)
     msg = Nodes(uuid, self.node.network_id, self.node.network_id,
                 self.reply_port, self.version, self.seal,
                 self.contacts)
     response = asyncio.Future()
     response.set_result(msg)
     lookup._handle_response(uuid, contact, response)
     self.assertEqual(lookup._lookup.call_count, 1)
     self.node.send_find.called_once_with(not_contacted, self.target,
                                          FindNode)
Exemple #11
0
 def test_handle_error(self):
     """
     The _handle_error method cleanly deals with the fallout of
     encountering an error generated from an interaction with a peer node.
     """
     patcher = mock.patch('drogulus.dht.lookup.log.info')
     mock_info = patcher.start()
     lookup = Lookup(FindNode, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     uuid = [uuid for uuid in lookup.pending_requests.keys()][0]
     pending_task = lookup.pending_requests[uuid]
     contact = lookup.shortlist[0]
     lookup._handle_error(uuid, contact, Exception('Foo'))
     self.assertNotIn(contact, lookup.shortlist)
     self.assertNotIn(uuid, lookup.pending_requests)
     self.assertTrue(pending_task.cancelled())
     # Log the error and associated exception (2 calls)
     self.assertEqual(mock_info.call_count, 2)
     self.assertEqual(lookup._lookup.call_count, 1)
     patcher.stop()
Exemple #12
0
 def test_handle_response_nodes_update_nearest_node(self):
     """
     If the response contains peer nodes that are nearer to the target then
     the nearest_node variable is updated to reflect this change of state
     and a new lookup call is kicked off.
     """
     lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     old_nearest_node = lookup.nearest_node
     uuids = [uuid for uuid in lookup.pending_requests.keys()]
     uuid = uuids[0]
     contact = lookup.shortlist[0]
     msg = Nodes(uuid, self.node.network_id, self.node.network_id,
                 self.reply_port, self.version, self.seal,
                 self.remote_nodes)
     response = asyncio.Future()
     response.set_result(msg)
     lookup._handle_response(uuid, contact, response)
     self.assertNotEqual(lookup.nearest_node, old_nearest_node)
     self.assertEqual(lookup.nearest_node, lookup.shortlist[0])
     self.assertEqual(lookup._lookup.call_count, 1)
Exemple #13
0
 def test_handle_response_nodes_update_nearest_node(self):
     """
     If the response contains peer nodes that are nearer to the target then
     the nearest_node variable is updated to reflect this change of state
     and a new lookup call is kicked off.
     """
     lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     old_nearest_node = lookup.nearest_node
     uuids = [uuid for uuid in lookup.pending_requests.keys()]
     uuid = uuids[0]
     contact = lookup.shortlist[0]
     msg = Nodes(uuid, self.node.network_id, self.node.network_id,
                 self.reply_port, self.version, self.seal,
                 self.remote_nodes)
     response = asyncio.Future()
     response.set_result(msg)
     lookup._handle_response(uuid, contact, response)
     self.assertNotEqual(lookup.nearest_node, old_nearest_node)
     self.assertEqual(lookup.nearest_node, lookup.shortlist[0])
     self.assertEqual(lookup._lookup.call_count, 1)
Exemple #14
0
 def test_handle_error(self):
     """
     The _handle_error method cleanly deals with the fallout of
     encountering an error generated from an interaction with a peer node.
     """
     patcher = mock.patch('drogulus.dht.lookup.log.info')
     mock_info = patcher.start()
     lookup = Lookup(FindNode, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     uuid = [uuid for uuid in lookup.pending_requests.keys()][0]
     pending_task = lookup.pending_requests[uuid]
     contact = lookup.shortlist[0]
     lookup.event_loop.call_soon = mock.MagicMock()
     lookup._handle_error(uuid, contact, Exception('Foo'))
     self.assertNotIn(contact, lookup.shortlist)
     self.assertNotIn(uuid, lookup.pending_requests)
     lookup.event_loop.call_soon.assert_called_once_with(
         pending_task.cancel)
     # Log the error and associated exception (2 calls)
     self.assertEqual(mock_info.call_count, 2)
     self.assertEqual(lookup._lookup.call_count, 1)
     patcher.stop()
Exemple #15
0
 def test_handle_response_nodes_do_not_update_nearest_node(self):
     """
     If the response contains peer nodes that are NOT closer to the target
     than the current nearest known node then nearest_node is NOT
     updated and a new lookup is NOT triggered.
     """
     lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     old_nearest_node = lookup.nearest_node
     uuids = [uuid for uuid in lookup.pending_requests.keys()]
     uuid = uuids[0]
     contact = lookup.shortlist[0]
     shortlist = tuple([(p.public_key, p.version, p.uri) for p
                        in lookup.shortlist])
     msg = Nodes(uuid, self.node.network_id, self.node.network_id,
                 self.reply_port, self.version, self.seal, shortlist)
     response = asyncio.Future()
     response.set_result(msg)
     lookup._handle_response(uuid, contact, response)
     self.assertEqual(lookup.nearest_node, old_nearest_node)
     self.assertEqual(lookup.nearest_node, lookup.shortlist[0])
     self.assertEqual(lookup._lookup.call_count, 0)
Exemple #16
0
 def test_handle_response_nodes_do_not_update_nearest_node(self):
     """
     If the response contains peer nodes that are NOT closer to the target
     than the current nearest known node then nearest_node is NOT
     updated and a new lookup is NOT triggered.
     """
     lookup = Lookup(FindValue, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     old_nearest_node = lookup.nearest_node
     uuids = [uuid for uuid in lookup.pending_requests.keys()]
     uuid = uuids[0]
     contact = lookup.shortlist[0]
     shortlist = tuple([(p.public_key, p.version, p.uri) for p
                        in lookup.shortlist])
     msg = Nodes(uuid, self.node.network_id, self.node.network_id,
                 self.reply_port, self.version, self.seal, shortlist)
     response = asyncio.Future()
     response.set_result(msg)
     lookup._handle_response(uuid, contact, response)
     self.assertEqual(lookup.nearest_node, old_nearest_node)
     self.assertEqual(lookup.nearest_node, lookup.shortlist[0])
     self.assertEqual(lookup._lookup.call_count, 0)
Exemple #17
0
 def test_handle_response_all_shortlist_contacted_return_nodes(self):
     """
     If there are no more pending requests and all the nodes in the
     shortlist have been contacted then return the shortlist of nearest
     peer nodes to the target if the lookup is a FindNode.
     """
     lookup = Lookup(FindNode, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     uuids = [uuid for uuid in lookup.pending_requests.keys()]
     uuid = uuids[0]
     contact = lookup.shortlist[0]
     # Only one item in pending_requests
     for i in range(1, len(uuids)):
         del lookup.pending_requests[uuids[i]]
     self.assertEqual(1, len(lookup.pending_requests))
     # Add K items from shortlist to the contacted set.
     for contact in lookup.shortlist:
         lookup.contacted.add(contact)
     # Cause the lookup to fire.
     msg = Nodes(uuid, self.node.network_id, self.node.network_id,
                 self.reply_port, self.version, self.seal,
                 self.contacts)
     response = asyncio.Future()
     response.set_result(msg)
     lookup._handle_response(uuid, contact, response)
     # The _lookup method should not be called.
     self.assertEqual(lookup._lookup.call_count, 0)
     # The lookup task has fired.
     self.assertTrue(lookup.done())
     # Check the result is the ordered shortlist of contacts that are
     # closest to the target.
     # It should be a list...
     self.assertIsInstance(lookup.result(), list)
     # It should be a list that's the lookup's shortlist...
     self.assertEqual(lookup.result(), lookup.shortlist)
     # It should be a list that's the lookup's shortlist in order.
     ordered = sort_peer_nodes(lookup.shortlist, self.target)
     self.assertEqual(lookup.result(), ordered)
Exemple #18
0
 def test_handle_response_all_shortlist_contacted_return_nodes(self):
     """
     If there are no more pending requests and all the nodes in the
     shortlist have been contacted then return the shortlist of nearest
     peer nodes to the target if the lookup is a FindNode.
     """
     lookup = Lookup(FindNode, self.target, self.node, self.event_loop)
     lookup._lookup = mock.MagicMock()
     uuids = [uuid for uuid in lookup.pending_requests.keys()]
     uuid = uuids[0]
     contact = lookup.shortlist[0]
     # Only one item in pending_requests
     for i in range(1, len(uuids)):
         del lookup.pending_requests[uuids[i]]
     self.assertEqual(1, len(lookup.pending_requests))
     # Add K items from shortlist to the contacted set.
     for contact in lookup.shortlist:
         lookup.contacted.add(contact)
     # Cause the lookup to fire.
     msg = Nodes(uuid, self.node.network_id, self.node.network_id,
                 self.reply_port, self.version, self.seal,
                 self.contacts)
     response = asyncio.Future()
     response.set_result(msg)
     lookup._handle_response(uuid, contact, response)
     # The _lookup method should not be called.
     self.assertEqual(lookup._lookup.call_count, 0)
     # The lookup task has fired.
     self.assertTrue(lookup.done())
     # Check the result is the ordered shortlist of contacts that are
     # closest to the target.
     # It should be a list...
     self.assertIsInstance(lookup.result(), list)
     # It should be a list that's the lookup's shortlist...
     self.assertEqual(lookup.result(), lookup.shortlist)
     # It should be a list that's the lookup's shortlist in order.
     ordered = sort_peer_nodes(lookup.shortlist, self.target)
     self.assertEqual(lookup.result(), ordered)