def test_key_in_range_handles_string(self): """ Ensures the keyInRange method decodes a string representation of a key correctly, before testing if it's within range. """ bucket = Bucket(1, 66) self.assertTrue(bucket.key_in_range('0xA'))
def test_key_in_range_no_too_high(self): """ Ensures a key just above the k-bucket's range is identified as out of range. """ bucket = Bucket(1, 5) self.assertFalse(bucket.key_in_range(7))
def test_key_in_range_no_too_low(self): """ Ensures a key just below the k-bucket's range is identified as out of range. """ bucket = Bucket(5, 9) self.assertFalse(bucket.key_in_range(2))
def test_get_contacts_empty(self): """ If the k-bucket is empty, the result of getContacts is an empty list. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) result = bucket.get_contacts() self.assertEqual(0, len(result))
def test_len(self): """ Ensures the number of nodes in the k-bucket is returned by __len__. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) contact = PeerNode("12345", "192.168.0.2", 8888, 123) bucket.add_contact(contact) self.assertEqual(1, len(bucket))
def test_get_contacts_all(self): """ Ensures get_contacts works as expected. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) for i in range(K): contact = PeerNode("%d" % i, "192.168.0.%d" % i, 9999, 123) bucket.add_contact(contact) result = bucket.get_contacts() self.assertEqual(20, len(result))
def test_remove_contact_with_bad_id(self): """ Ensures a ValueError exception is raised if one attempts to remove a non-existent contact from a k-bucket. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) contact = PeerNode("12345", "192.168.0.2", 8888, 123) bucket.add_contact(contact) with self.assertRaises(ValueError): bucket.remove_contact("54321")
def test_get_contacts_count_too_big(self): """ If the "count" argument is bigger than the number of contacts in the bucket then all the contacts are returned. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) for i in range(10): contact = PeerNode("%d" % i, "192.168.0.%d" % i, 9999, 123) bucket.add_contact(contact) result = bucket.get_contacts(count=20) self.assertEqual(10, len(result))
def test_get_contact_with_bad_id(self): """ Ensures a ValueError exception is raised if one attempts to get a contact from the k-bucket with an id that doesn't exist in the k-bucket. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) contact = PeerNode("12345", "192.168.0.2", 8888, 123) bucket.add_contact(contact) with self.assertRaises(ValueError): bucket.get_contact("54321")
def test_get_contacts_with_exclusion(self): """ If a contact is passed as the excludeContact argument then it won't be in the result list. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) for i in range(K): contact = PeerNode("%d" % i, "192.168.0.%d" % i, 9999, 123) bucket.add_contact(contact) result = bucket.get_contacts(count=20, exclude_contact=contact) self.assertEqual(19, len(result)) self.assertFalse(contact in result)
def test_add_contact_to_full_bucket(self): """ Ensures that if one attempts to add a contact to a bucket whose size is greater than the constant K, then the BucketFull exception is raised. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) for i in range(K): contact = PeerNode("%d" % i, "192.168.0.%d" % i, 9999, 123) bucket.add_contact(contact) with self.assertRaises(BucketFull): contact_too_many = PeerNode("12345", "192.168.0.2", 8888, 123) bucket.add_contact(contact_too_many)
def test_get_contact(self): """ Ensures it is possible to get a contact from the k-bucket with a valid id. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) for i in range(K): contact = PeerNode(PUBLIC_KEY, "192.168.0.%d" % i, 9999, 123) contact.network_id = hex(i) bucket.add_contact(contact) for i in range(K): self.assertTrue(bucket.get_contact(hex(i)), "Could not get contact with id %d" % i)
def test_remove_contact(self): """ Ensures it is possible to remove a contact with a certain ID from the k-bucket. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) for i in range(K): contact = PeerNode(PUBLIC_KEY, "192.168.0.%d" % i, 9999, 123) contact.network_id = hex(i) bucket.add_contact(contact) for i in range(K): bucket.remove_contact(hex(i)) self.assertFalse(hex(i) in bucket._contacts, "Could not remove contact with id %s" % hex(i))
def test_get_refresh_list(self): """ Ensures that only keys from stale k-buckets are returned. """ parent_node_id = '0xdeadbeef' r = RoutingTable(parent_node_id) bucket1 = Bucket(1, 2) # Set the lastAccessed flag on bucket 1 to be out of date bucket1.last_accessed = int(time.time()) - 3700 r._buckets[0] = bucket1 bucket2 = Bucket(2, 3) bucket2.last_accessed = int(time.time()) r._buckets.append(bucket2) expected = 1 result = r.get_refresh_list(0) self.assertEqual(1, len(result)) self.assertEqual(expected, int(result[0], 0))
def test_get_forced_refresh_list(self): """ Ensures that keys from all k-buckets (no matter if they're stale or not) are returned. """ parent_node_id = '0xdeadbeef' r = RoutingTable(parent_node_id) bucket1 = Bucket(1, 2) # Set the lastAccessed flag on bucket 1 to be out of date bucket1.last_accessed = int(time.time()) - 3700 r._buckets[0] = bucket1 bucket2 = Bucket(2, 3) bucket2.last_accessed = int(time.time()) r._buckets.append(bucket2) result = r.get_refresh_list(0, True) # Even though bucket 2 is not stale it still has a key for it in # the result. self.assertEqual(2, len(result)) self.assertEqual(1, int(result[0], 0)) self.assertEqual(2, int(result[1], 0))
def test_add_existing_contact(self): """ Ensures that if an existing contact is re-added to the kbucket it is simply moved to the end of the _contacts list (as specified in the original Kademlia paper) signifying that it is the most recently seen contact within this bucket. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) contact1 = PeerNode("1", "192.168.0.1", 9999, 123) bucket.add_contact(contact1) contact2 = PeerNode("2", "192.168.0.2", 8888, 123) bucket.add_contact(contact2) bucket.add_contact(contact1) # There should still only be two contacts in the bucket. self.assertEqual(2, len(bucket._contacts), "Too many contacts in the k-bucket.") # The end contact should be the most recently added contact. self.assertEqual(contact1, bucket._contacts[-1:][0], "The expected most recent contact is wrong.")
def test_add_new_contact(self): """ Ensures that a new contact, when added to the kbucket is appended to the end of the _contacts list (as specified in the original Kademlia paper) signifying that it is the most recently seen contact within this bucket. """ range_min = 12345 range_max = 98765 bucket = Bucket(range_min, range_max) contact1 = PeerNode(PUBLIC_KEY, "192.168.0.1", 9999, 123) contact1.network_id = hex(1) bucket.add_contact(contact1) self.assertEqual(1, len(bucket._contacts), "Single contact not added to k-bucket.") contact2 = PeerNode(PUBLIC_KEY, "192.168.0.2", 8888, 123) contact2.network_id = hex(2) bucket.add_contact(contact2) self.assertEqual(2, len(bucket._contacts), "K-bucket's contact list not the expected length.") self.assertEqual(contact2, bucket._contacts[-1:][0], "K-bucket's most recent (last) contact wrong.")
def test_split_bucket(self): """ Ensures that the correct bucket is split in two and that the contacts are found in the right place. """ parent_node_id = '0xdeadbeef' r = RoutingTable(parent_node_id) bucket = Bucket(0, 100) contact1 = PeerNode(PUBLIC_KEY, '192.168.0.1', 9999, 0) contact1.network_id = hex(20) bucket.add_contact(contact1) contact2 = PeerNode(PUBLIC_KEY, '192.168.0.2', 8888, 0) contact2.network_id = hex(40) bucket.add_contact(contact2) contact3 = PeerNode(PUBLIC_KEY, '192.168.0.3', 8888, 0) contact3.network_id = hex(60) bucket.add_contact(contact3) contact4 = PeerNode(PUBLIC_KEY, '192.168.0.4', 8888, 0) contact4.network_id = hex(80) bucket.add_contact(contact4) r._buckets[0] = bucket # Sanity check self.assertEqual(1, len(r._buckets)) r._split_bucket(0) # Two buckets! self.assertEqual(2, len(r._buckets)) bucket1 = r._buckets[0] bucket2 = r._buckets[1] # Ensure the right number of contacts are in each bucket in the correct # order (most recently added at the head of the list). self.assertEqual(2, len(bucket1._contacts)) self.assertEqual(2, len(bucket2._contacts)) self.assertEqual(contact1, bucket1._contacts[0]) self.assertEqual(contact2, bucket1._contacts[1]) self.assertEqual(contact3, bucket2._contacts[0]) self.assertEqual(contact4, bucket2._contacts[1]) # Split the new bucket again, ensuring that only the target bucket is # modified. r._split_bucket(1) self.assertEqual(3, len(r._buckets)) bucket3 = r._buckets[2] # bucket1 remains un-changed self.assertEqual(2, len(bucket1._contacts)) # bucket2 only contains the lower half of its original contacts. self.assertEqual(1, len(bucket2._contacts)) self.assertEqual(contact3, bucket2._contacts[0]) # bucket3 now contains the upper half of the original contacts. self.assertEqual(1, len(bucket3._contacts)) self.assertEqual(contact4, bucket3._contacts[0]) # Split the bucket at position 0 and ensure the resulting buckets are # in the correct position with the correct content. r._split_bucket(0) self.assertEqual(4, len(r._buckets)) bucket1, bucket2, bucket3, bucket4 = r._buckets self.assertEqual(1, len(bucket1._contacts)) self.assertEqual(contact1, bucket1._contacts[0]) self.assertEqual(1, len(bucket2._contacts)) self.assertEqual(contact2, bucket2._contacts[0]) self.assertEqual(1, len(bucket3._contacts)) self.assertEqual(contact3, bucket3._contacts[0]) self.assertEqual(1, len(bucket4._contacts)) self.assertEqual(contact4, bucket4._contacts[0])
def test_key_in_range_yes(self): """ Ensures that a key within the appropriate range is identified as such. """ bucket = Bucket(1, 9) self.assertTrue(bucket.key_in_range(2))