def test_remove_contact_with_cached_replacement(self): """ Ensures that the removed contact is replaced by the most up-to-date contact in the affected k-bucket's cache. """ parent_node_id = hex((2 ** 512) + 1)[2:] r = RoutingTable(parent_node_id) cache_key = (r._buckets[0].range_min, r._buckets[0].range_max) contact1 = PeerNode(PUBLIC_KEY, self.version, 'netstring://192.168.0.1:9999/', 0) contact2 = PeerNode(BAD_PUBLIC_KEY, self.version, 'netstring://192.168.0.1:9999/', 0) r.add_contact(contact1) r.add_contact(contact2) contact2.failed_RPCs = constants.ALLOWED_RPC_FAILS # Add something into the cache. contact3 = PeerNode(PUBLIC_KEY + 'foo', self.version, 'netstring://192.168.0.1:9999/', 0) contact3.network_id = '3' r._replacement_cache[cache_key] = [contact3, ] # Sanity check self.assertEqual(len(r._buckets[0]), 2) self.assertEqual(len(r._replacement_cache[cache_key]), 1) r.remove_contact(BAD_PUBLIC_KEY) self.assertEqual(len(r._buckets[0]), 2) self.assertEqual(contact1, r._buckets[0]._contacts[0]) self.assertEqual(contact3, r._buckets[0]._contacts[1]) self.assertEqual(len(r._replacement_cache[cache_key]), 0)
def test_remove_contact_with_cached_replacement(self): """ Ensures that the removed contact is replaced by the most up-to-date contact in the affected k-bucket's cache. """ parent_node_id = 'abc' r = RoutingTable(parent_node_id) contact1 = Contact('a', '192.168.0.1', 9999, self.version, 0) contact2 = Contact('b', '192.168.0.2', 9999, self.version, 0) r.add_contact(contact1) # Contact 2 will have the wrong number of failedRPCs r.add_contact(contact2) contact2.failed_RPCs = constants.ALLOWED_RPC_FAILS # Add something into the cache. contact3 = Contact('c', '192.168.0.3', 9999, self.version, 0) r._replacement_cache[0] = [contact3, ] # Sanity check self.assertEqual(len(r._buckets[0]), 2) self.assertEqual(len(r._replacement_cache[0]), 1) r.remove_contact('b') self.assertEqual(len(r._buckets[0]), 2) self.assertEqual(contact1, r._buckets[0]._contacts[0]) self.assertEqual(contact3, r._buckets[0]._contacts[1]) self.assertEqual(len(r._replacement_cache[0]), 0)
def test_remove_contact_with_not_enough_RPC_fails(self): """ Ensures that the contact is not removed if it's failedRPCs counter is less than constants.ALLOWED_RPC_FAILS """ parent_node_id = 'abc' r = RoutingTable(parent_node_id) contact1 = Contact('a', '192.168.0.1', 9999, self.version, 0) contact2 = Contact('b', '192.168.0.2', 9999, self.version, 0) r.add_contact(contact1) r.add_contact(contact2) # Sanity check self.assertEqual(len(r._buckets[0]), 2) r.remove_contact('b') self.assertEqual(len(r._buckets[0]), 2)
def test_remove_contact_with_not_enough_RPC_but_forced(self): """ Ensures that the contact is removed despite it's failedRPCs counter being less than constants.ALLOWED_RPC_FAILS because the 'forced' flag is used. """ parent_node_id = 'abc' r = RoutingTable(parent_node_id) contact1 = Contact('a', '192.168.0.1', 9999, self.version, 0) contact2 = Contact('b', '192.168.0.2', 9999, self.version, 0) r.add_contact(contact1) r.add_contact(contact2) # Sanity check self.assertEqual(len(r._buckets[0]), 2) r.remove_contact('b', forced=True) self.assertEqual(len(r._buckets[0]), 1)
def test_remove_contact_with_not_enough_RPC_but_forced(self): """ Ensures that the contact is removed despite it's failedRPCs counter being less than constants.ALLOWED_RPC_FAILS because the 'forced' flag is used. """ parent_node_id = 'deadbeef' r = RoutingTable(parent_node_id) contact1 = PeerNode(PUBLIC_KEY, self.version, 'netstring://192.168.0.1:9999/', 0) contact2 = PeerNode(BAD_PUBLIC_KEY, self.version, 'netstring://192.168.0.1:9999/', 0) r.add_contact(contact1) r.add_contact(contact2) # Sanity check self.assertEqual(len(r._buckets[0]), 2) r.remove_contact(BAD_PUBLIC_KEY, forced=True) self.assertEqual(len(r._buckets[0]), 1)
def test_remove_contact(self): """ Ensures that a contact is removed, given that it's failedRPCs counter exceeds or is equal to constants.ALLOWED_RPC_FAILS """ parent_node_id = 'abc' r = RoutingTable(parent_node_id) contact1 = Contact('a', '192.168.0.1', 9999, self.version, 0) contact2 = Contact('b', '192.168.0.2', 9999, self.version, 0) r.add_contact(contact1) # Contact 2 will have the wrong number of failedRPCs r.add_contact(contact2) contact2.failed_RPCs = constants.ALLOWED_RPC_FAILS # Sanity check self.assertEqual(len(r._buckets[0]), 2) r.remove_contact('b') self.assertEqual(len(r._buckets[0]), 1) self.assertEqual(contact1, r._buckets[0]._contacts[0])
def test_remove_contact_with_not_enough_RPC_fails(self): """ Ensures that the contact is not removed if it's failedRPCs counter is less than constants.ALLOWED_RPC_FAILS """ parent_node_id = 'deadbeef' r = RoutingTable(parent_node_id) contact1 = PeerNode(PUBLIC_KEY, self.version, 'netstring://192.168.0.1:9999/', 0) contact1.network_id = 'a' contact2 = PeerNode(PUBLIC_KEY, self.version, 'netstring://192.168.0.1:9999/', 0) contact2.network_id = 'b' r.add_contact(contact1) r.add_contact(contact2) # Sanity check self.assertEqual(len(r._buckets[0]), 2) r.remove_contact('b') self.assertEqual(len(r._buckets[0]), 2)
def test_remove_contact(self): """ Ensures that a contact is removed, given that it's failedRPCs counter exceeds or is equal to constants.ALLOWED_RPC_FAILS """ parent_node_id = 'deadbeef' r = RoutingTable(parent_node_id) contact1 = PeerNode(PUBLIC_KEY, self.version, 'netstring://192.168.0.1:9999/', 0) contact2 = PeerNode(BAD_PUBLIC_KEY, self.version, 'netstring://192.168.0.1:9999/', 0) r.add_contact(contact1) # contact2 will have the wrong number of failedRPCs r.add_contact(contact2) contact2.failed_RPCs = constants.ALLOWED_RPC_FAILS # Sanity check self.assertEqual(len(r._buckets[0]), 2) r.remove_contact(BAD_PUBLIC_KEY) self.assertEqual(len(r._buckets[0]), 1) self.assertEqual(contact1, r._buckets[0]._contacts[0])
def test_blacklist_public_key(self): """ Ensure that a contact is removed from the routing table and blacklist given a matching public_key. """ parent_node_id = 'deadbeef' r = RoutingTable(parent_node_id) contact = PeerNode(PUBLIC_KEY, '192.168.0.1', 9999, 0) r.remove_contact = MagicMock() r._blacklist_public_key(PUBLIC_KEY) r.remove_contact.called_once_with(contact, True) self.assertIn(contact.public_key, r._blacklist)
def test_remove_contact_removes_from_replacement_cache(self): """ Ensures that if a contact is signalled to be removed it is also cleared from the replacement_cache that would otherwise be another route for it to be re-added to the routing table. """ parent_node_id = 'abc' r = RoutingTable(parent_node_id) contact1 = Contact('a', '192.168.0.1', 9999, self.version, 0) contact2 = Contact('b', '192.168.0.2', 9999, self.version, 0) r.add_contact(contact1) r.add_contact(contact2) r._replacement_cache[0] = [] r._replacement_cache[0].append(contact2) # Sanity check self.assertEqual(len(r._buckets[0]), 2) self.assertEqual(len(r._replacement_cache[0]), 1) r.remove_contact('b', forced=True) self.assertEqual(len(r._buckets[0]), 1) self.assertNotIn(contact2, r._replacement_cache)
def test_blacklist(self): """ Ensures a misbehaving peer is correctly blacklisted. The remove_contact method is called and the contact's id is added to the _blacklist set. """ parent_node_id = 'abc' r = RoutingTable(parent_node_id) contact = Contact('abc', '192.168.0.1', 9999, 0) r.remove_contact = MagicMock() r.blacklist(contact) r.remove_contact.called_once_with(contact, True) self.assertIn(contact.id, r._blacklist)
def test_blacklist(self): """ Ensures a misbehaving peer is correctly blacklisted. The remove_contact method is called and the contact's public key is added to the _blacklist set. """ parent_node_id = 'deadbeef' r = RoutingTable(parent_node_id) contact = PeerNode(PUBLIC_KEY, '192.168.0.1', 9999, 0) r.remove_contact = MagicMock() r.blacklist(contact) r.remove_contact.called_once_with(contact, True) self.assertIn(contact.public_key, r._blacklist)
def test_remove_contact_removes_from_replacement_cache(self): """ Ensures that if a contact is signalled to be removed it is also cleared from the replacement_cache that would otherwise be another route for it to be re-added to the routing table. """ parent_node_id = 'deadbeef' r = RoutingTable(parent_node_id) contact1 = PeerNode(PUBLIC_KEY, self.version, 'netstring://192.168.0.1:9999/', 0) contact2 = PeerNode(BAD_PUBLIC_KEY, self.version, 'netstring://192.168.0.1:9999/', 0) r.add_contact(contact1) r.add_contact(contact2) cache_key = (r._buckets[0].range_min, r._buckets[0].range_max) r._replacement_cache[cache_key] = [] r._replacement_cache[cache_key].append(contact2) # Sanity check self.assertEqual(len(r._buckets[0]), 2) self.assertEqual(len(r._replacement_cache[cache_key]), 1) r.remove_contact(BAD_PUBLIC_KEY, forced=True) self.assertEqual(len(r._buckets[0]), 1) self.assertNotIn(contact2, r._replacement_cache[cache_key])
def test_remove_contact_with_unknown_contact(self): """ Ensures that attempting to remove a non-existent contact results in a ValueError exception. """ parent_node_id = 'abc' r = RoutingTable(parent_node_id) contact1 = Contact('a', '192.168.0.1', 9999, self.version, 0) r.add_contact(contact1) # Sanity check self.assertEqual(len(r._buckets[0]), 1) result = r.remove_contact('b') self.assertEqual(None, result) self.assertEqual(len(r._buckets[0]), 1) self.assertEqual(contact1, r._buckets[0]._contacts[0])
def test_remove_contact_with_unknown_contact(self): """ Ensures that attempting to remove a non-existent contact results in no change. """ parent_node_id = 'deadbeef' r = RoutingTable(parent_node_id) contact1 = PeerNode(PUBLIC_KEY, self.version, 'netstring://192.168.0.1:9999/', 0) contact1.network_id = 'a' r.add_contact(contact1) # Sanity check self.assertEqual(len(r._buckets[0]), 1) result = r.remove_contact('b') self.assertEqual(None, result) self.assertEqual(len(r._buckets[0]), 1) self.assertEqual(contact1, r._buckets[0]._contacts[0])