示例#1
0
 def setUp(self):
     h = hashlib.sha384()
     h.update('node1')
     self.contact_manager = ContactManager()
     self.nodeID = h.digest()
     self.protocol = FakeRPCProtocol()
     self.routingTable = TreeRoutingTable(self.nodeID)
示例#2
0
 def setUp(self):
     self.clock = task.Clock()
     self.contact_manager = ContactManager(self.clock.seconds)
     self.contact = self.contact_manager.make_contact(
         generate_id(), "127.0.0.1", 4444, None)
     self.clock.advance(3600)
     self.assertTrue(self.contact.contact_is_good is None)
 def setUp(self):
     self.contact_manager = ContactManager()
     self.node_ids = [generate_id(), generate_id(), generate_id()]
     make_contact = self.contact_manager.make_contact
     self.first_contact = make_contact(self.node_ids[1], '127.0.0.1', 1000, None, 1)
     self.second_contact = make_contact(self.node_ids[0], '192.168.0.1', 1000, None, 32)
     self.second_contact_second_reference = make_contact(self.node_ids[0], '192.168.0.1', 1000, None, 32)
     self.first_contact_different_values = make_contact(self.node_ids[1], '192.168.1.20', 1000, None, 50)
示例#4
0
class ContactOperatorsTest(unittest.TestCase):
    """ Basic tests case for boolean operators on the Contact class """
    def setUp(self):
        self.contact_manager = ContactManager()
        self.node_ids = [generate_id(), generate_id(), generate_id()]
        self.firstContact = self.contact_manager.make_contact(
            self.node_ids[1], '127.0.0.1', 1000, None, 1)
        self.secondContact = self.contact_manager.make_contact(
            self.node_ids[0], '192.168.0.1', 1000, None, 32)
        self.secondContactCopy = self.contact_manager.make_contact(
            self.node_ids[0], '192.168.0.1', 1000, None, 32)
        self.firstContactDifferentValues = self.contact_manager.make_contact(
            self.node_ids[1], '192.168.1.20', 1000, None, 50)
        self.assertRaises(ValueError, self.contact_manager.make_contact,
                          self.node_ids[1], '192.168.1.20', 100000, None)
        self.assertRaises(ValueError, self.contact_manager.make_contact,
                          self.node_ids[1], '192.168.1.20.1', 1000, None)
        self.assertRaises(ValueError, self.contact_manager.make_contact,
                          self.node_ids[1], 'this is not an ip', 1000, None)
        self.assertRaises(ValueError, self.contact_manager.make_contact,
                          "this is not a node id", '192.168.1.20.1', 1000,
                          None)

    def testNoDuplicateContactObjects(self):
        self.assertTrue(self.secondContact is self.secondContactCopy)
        self.assertTrue(
            self.firstContact is not self.firstContactDifferentValues)

    def testBoolean(self):
        """ Test "equals" and "not equals" comparisons """
        self.failIfEqual(self.firstContact, self.secondContact,
                         'Contacts with different IDs should not be equal.')
        self.failUnlessEqual(
            self.firstContact, self.firstContactDifferentValues,
            'Contacts with same IDs should be equal, even if their other values differ.'
        )
        self.failUnlessEqual(
            self.secondContact, self.secondContactCopy,
            'Different copies of the same Contact instance should be equal')

    def testIllogicalComparisons(self):
        """ Test comparisons with non-Contact and non-str types """
        msg = '"{}" operator: Contact object should not be equal to {} type'
        for item in (123, [1, 2, 3], {'key': 'value'}):
            self.failIfEqual(self.firstContact, item,
                             msg.format('eq',
                                        type(item).__name__))
            self.failUnless(self.firstContact != item,
                            msg.format('ne',
                                       type(item).__name__))

    def testCompactIP(self):
        self.assertEqual(self.firstContact.compact_ip(), '\x7f\x00\x00\x01')
        self.assertEqual(self.secondContact.compact_ip(), '\xc0\xa8\x00\x01')
class ContactTest(unittest.TestCase):
    """ Basic tests case for boolean operators on the Contact class """
    def setUp(self):
        self.contact_manager = ContactManager()
        self.node_ids = [generate_id(), generate_id(), generate_id()]
        make_contact = self.contact_manager.make_contact
        self.first_contact = make_contact(self.node_ids[1], '127.0.0.1', 1000, None, 1)
        self.second_contact = make_contact(self.node_ids[0], '192.168.0.1', 1000, None, 32)
        self.second_contact_second_reference = make_contact(self.node_ids[0], '192.168.0.1', 1000, None, 32)
        self.first_contact_different_values = make_contact(self.node_ids[1], '192.168.1.20', 1000, None, 50)

    def test_make_contact_error_cases(self):
        self.assertRaises(
            ValueError, self.contact_manager.make_contact, self.node_ids[1], '192.168.1.20', 100000, None)
        self.assertRaises(
            ValueError, self.contact_manager.make_contact, self.node_ids[1], '192.168.1.20.1', 1000, None)
        self.assertRaises(
            ValueError, self.contact_manager.make_contact, self.node_ids[1], 'this is not an ip', 1000, None)
        self.assertRaises(
            ValueError, self.contact_manager.make_contact, b'not valid node id', '192.168.1.20.1', 1000, None)

    def test_no_duplicate_contact_objects(self):
        self.assertTrue(self.second_contact is self.second_contact_second_reference)
        self.assertTrue(self.first_contact is not self.first_contact_different_values)

    def test_boolean(self):
        """ Test "equals" and "not equals" comparisons """
        self.assertNotEqual(
            self.first_contact, self.contact_manager.make_contact(
                self.first_contact.id, self.first_contact.address, self.first_contact.port + 1, None, 32
            )
        )
        self.assertNotEqual(
            self.first_contact, self.contact_manager.make_contact(
                self.first_contact.id, '193.168.1.1', self.first_contact.port, None, 32
            )
        )
        self.assertNotEqual(
            self.first_contact, self.contact_manager.make_contact(
                generate_id(), self.first_contact.address, self.first_contact.port, None, 32
            )
        )
        self.assertEqual(self.second_contact, self.second_contact_second_reference)

    def test_compact_ip(self):
        self.assertEqual(self.first_contact.compact_ip(), b'\x7f\x00\x00\x01')
        self.assertEqual(self.second_contact.compact_ip(), b'\xc0\xa8\x00\x01')

    def test_id_log(self):
        self.assertEqual(self.first_contact.log_id(False), hexlify(self.node_ids[1]))
        self.assertEqual(self.first_contact.log_id(True),  hexlify(self.node_ids[1])[:8])
示例#6
0
 def setUp(self):
     self.contact_manager = ContactManager()
     self.node_ids = [generate_id(), generate_id(), generate_id()]
     self.firstContact = self.contact_manager.make_contact(
         self.node_ids[1], '127.0.0.1', 1000, None, 1)
     self.secondContact = self.contact_manager.make_contact(
         self.node_ids[0], '192.168.0.1', 1000, None, 32)
     self.secondContactCopy = self.contact_manager.make_contact(
         self.node_ids[0], '192.168.0.1', 1000, None, 32)
     self.firstContactDifferentValues = self.contact_manager.make_contact(
         self.node_ids[1], '192.168.1.20', 1000, None, 50)
     self.assertRaises(ValueError, self.contact_manager.make_contact,
                       self.node_ids[1], '192.168.1.20', 100000, None)
     self.assertRaises(ValueError, self.contact_manager.make_contact,
                       self.node_ids[1], '192.168.1.20.1', 1000, None)
     self.assertRaises(ValueError, self.contact_manager.make_contact,
                       self.node_ids[1], 'this is not an ip', 1000, None)
     self.assertRaises(ValueError, self.contact_manager.make_contact,
                       "this is not a node id", '192.168.1.20.1', 1000,
                       None)
示例#7
0
class TestContactLastRequested(unittest.TestCase):
    def setUp(self):
        self.clock = task.Clock()
        self.contact_manager = ContactManager(self.clock.seconds)
        self.contact = self.contact_manager.make_contact(
            generate_id(), "127.0.0.1", 4444, None)
        self.clock.advance(1)
        self.contact.update_last_replied()
        self.clock.advance(3600)
        self.assertTrue(self.contact.contact_is_good is None)

    def test_previous_replied_then_requested(self):
        # it requests
        self.contact.update_last_requested()
        self.assertTrue(self.contact.contact_is_good is True)

        # it goes stale
        self.clock.advance(constants.checkRefreshInterval - 1)
        self.assertTrue(self.contact.contact_is_good is True)
        self.clock.advance(1)
        self.assertTrue(self.contact.contact_is_good is None)

    def test_previous_replied_then_requested_then_failed(self):
        # it requests
        self.contact.update_last_requested()
        self.assertTrue(self.contact.contact_is_good is True)
        self.clock.advance(1)

        # it fails twice in a row
        self.contact.update_last_failed()
        self.clock.advance(1)
        self.contact.update_last_failed()
        self.assertTrue(self.contact.contact_is_good is False)
        self.clock.advance(1)

        # it requests
        self.contact.update_last_requested()
        self.clock.advance(1)
        self.assertTrue(self.contact.contact_is_good is False)

        # it goes stale
        self.clock.advance((constants.refreshTimeout / 4) - 2)
        self.assertTrue(self.contact.contact_is_good is False)
        self.clock.advance(1)
        self.assertTrue(self.contact.contact_is_good is False)
示例#8
0
    def __init__(self,
                 clock=None,
                 callLater=None,
                 resolve=None,
                 listenUDP=None):
        if not listenUDP or not resolve or not callLater or not clock:
            from twisted.internet import reactor
            listenUDP = listenUDP or reactor.listenUDP
            resolve = resolve or reactor.resolve
            callLater = callLater or reactor.callLater
            clock = clock or reactor

        self.clock = clock
        self.contact_manager = ContactManager(self.clock.seconds)
        self.reactor_listenUDP = listenUDP
        self.reactor_resolve = resolve
        self.call_later_manager = CallLaterManager(callLater)
        self.reactor_callLater = self.call_later_manager.call_later
        self.reactor_callSoon = self.call_later_manager.call_soon

        self._listeningPort = None  # object implementing Twisted
 def setUp(self):
     self.address_generator = address_generator()
     self.contact_manager = ContactManager()
     self.kbucket = kbucket.KBucket(0, 2**constants.key_bits, generate_id())
class KBucketTest(unittest.TestCase):
    """ Test case for the KBucket class """
    def setUp(self):
        self.address_generator = address_generator()
        self.contact_manager = ContactManager()
        self.kbucket = kbucket.KBucket(0, 2**constants.key_bits, generate_id())

    def testAddContact(self):
        """ Tests if the bucket handles contact additions/updates correctly """
        # Test if contacts can be added to empty list
        # Add k contacts to bucket
        for i in range(constants.k):
            tmpContact = self.contact_manager.make_contact(
                generate_id(), next(self.address_generator), 4444, 0, None)
            self.kbucket.addContact(tmpContact)
            self.assertEqual(
                self.kbucket._contacts[i], tmpContact,
                "Contact in position %d not the same as the newly-added contact"
                % i)

        # Test if contact is not added to full list
        tmpContact = self.contact_manager.make_contact(
            generate_id(), next(self.address_generator), 4444, 0, None)
        self.assertRaises(kbucket.BucketFull, self.kbucket.addContact,
                          tmpContact)

        # Test if an existing contact is updated correctly if added again
        existingContact = self.kbucket._contacts[0]
        self.kbucket.addContact(existingContact)
        self.assertEqual(
            self.kbucket._contacts.index(existingContact),
            len(self.kbucket._contacts) - 1,
            'Contact not correctly updated; it should be at the end of the list of contacts'
        )

    def testGetContacts(self):
        # try and get 2 contacts from empty list
        result = self.kbucket.getContacts(2)
        self.assertFalse(
            len(result) != 0,
            "Returned list should be empty; returned list length: %d" %
            (len(result)))

        # Add k-2 contacts
        node_ids = []
        if constants.k >= 2:
            for i in range(constants.k - 2):
                node_ids.append(generate_id())
                tmpContact = self.contact_manager.make_contact(
                    node_ids[-1], next(self.address_generator), 4444, 0, None)
                self.kbucket.addContact(tmpContact)
        else:
            # add k contacts
            for i in range(constants.k):
                node_ids.append(generate_id())
                tmpContact = self.contact_manager.make_contact(
                    node_ids[-1], next(self.address_generator), 4444, 0, None)
                self.kbucket.addContact(tmpContact)

        # try to get too many contacts
        # requested count greater than bucket size; should return at most k contacts
        contacts = self.kbucket.getContacts(constants.k + 3)
        self.assertTrue(
            len(contacts) <= constants.k,
            'Returned list should not have more than k entries!')

        # verify returned contacts in list
        for node_id, i in zip(node_ids, range(constants.k - 2)):
            self.assertFalse(
                self.kbucket._contacts[i].id != node_id,
                "Contact in position %s not same as added contact" % (str(i)))

        # try to get too many contacts
        # requested count one greater than number of contacts
        if constants.k >= 2:
            result = self.kbucket.getContacts(constants.k - 1)
            self.assertFalse(
                len(result) != constants.k - 2,
                "Too many contacts in returned list %s - should be %s" %
                (len(result), constants.k - 2))
        else:
            result = self.kbucket.getContacts(constants.k - 1)
            # if the count is <= 0, it should return all of it's contats
            self.assertFalse(
                len(result) != constants.k,
                "Too many contacts in returned list %s - should be %s" %
                (len(result), constants.k - 2))
            result = self.kbucket.getContacts(constants.k - 3)
            self.assertFalse(
                len(result) != constants.k - 3,
                "Too many contacts in returned list %s - should be %s" %
                (len(result), constants.k - 3))

    def testRemoveContact(self):
        # try remove contact from empty list
        rmContact = self.contact_manager.make_contact(
            generate_id(), next(self.address_generator), 4444, 0, None)
        self.assertRaises(ValueError, self.kbucket.removeContact, rmContact)

        # Add couple contacts
        for i in range(constants.k - 2):
            tmpContact = self.contact_manager.make_contact(
                generate_id(), next(self.address_generator), 4444, 0, None)
            self.kbucket.addContact(tmpContact)

        # try remove contact from empty list
        self.kbucket.addContact(rmContact)
        result = self.kbucket.removeContact(rmContact)
        self.assertFalse(rmContact in self.kbucket._contacts,
                         "Could not remove contact from bucket")
 def setUp(self):
     self.contact_manager = ContactManager()
     self.nodeID = generate_id(b'node1')
     self.protocol = FakeRPCProtocol()
     self.routingTable = TreeRoutingTable(self.nodeID)
class TreeRoutingTableTest(unittest.TestCase):
    """ Test case for the RoutingTable class """
    def setUp(self):
        self.contact_manager = ContactManager()
        self.nodeID = generate_id(b'node1')
        self.protocol = FakeRPCProtocol()
        self.routingTable = TreeRoutingTable(self.nodeID)

    def test_distance(self):
        """ Test to see if distance method returns correct result"""
        d = Distance(bytes((170,) * 48))
        result = d(bytes((85,) * 48))
        expected = int(hexlify(bytes((255,) * 48)), 16)
        self.assertEqual(result, expected)

    @defer.inlineCallbacks
    def test_add_contact(self):
        """ Tests if a contact can be added and retrieved correctly """
        # Create the contact
        contact_id = generate_id(b'node2')
        contact = self.contact_manager.make_contact(contact_id, '127.0.0.1', 9182, self.protocol)
        # Now add it...
        yield self.routingTable.addContact(contact)
        # ...and request the closest nodes to it (will retrieve it)
        closest_nodes = self.routingTable.findCloseNodes(contact_id)
        self.assertEqual(len(closest_nodes), 1)
        self.assertIn(contact, closest_nodes)

    @defer.inlineCallbacks
    def test_get_contact(self):
        """ Tests if a specific existing contact can be retrieved correctly """
        contact_id = generate_id(b'node2')
        contact = self.contact_manager.make_contact(contact_id, '127.0.0.1', 9182, self.protocol)
        # Now add it...
        yield self.routingTable.addContact(contact)
        # ...and get it again
        same_contact = self.routingTable.getContact(contact_id)
        self.assertEqual(contact, same_contact, 'getContact() should return the same contact')

    @defer.inlineCallbacks
    def test_add_parent_node_as_contact(self):
        """
        Tests the routing table's behaviour when attempting to add its parent node as a contact
        """
        # Create a contact with the same ID as the local node's ID
        contact = self.contact_manager.make_contact(self.nodeID, '127.0.0.1', 9182, self.protocol)
        # Now try to add it
        yield self.routingTable.addContact(contact)
        # ...and request the closest nodes to it using FIND_NODE
        closest_nodes = self.routingTable.findCloseNodes(self.nodeID, constants.k)
        self.assertNotIn(contact, closest_nodes, 'Node added itself as a contact')

    @defer.inlineCallbacks
    def test_remove_contact(self):
        """ Tests contact removal """
        # Create the contact
        contact_id = generate_id(b'node2')
        contact = self.contact_manager.make_contact(contact_id, '127.0.0.1', 9182, self.protocol)
        # Now add it...
        yield self.routingTable.addContact(contact)
        # Verify addition
        self.assertEqual(len(self.routingTable._buckets[0]), 1, 'Contact not added properly')
        # Now remove it
        self.routingTable.removeContact(contact)
        self.assertEqual(len(self.routingTable._buckets[0]), 0, 'Contact not removed properly')

    @defer.inlineCallbacks
    def test_split_bucket(self):
        """ Tests if the the routing table correctly dynamically splits k-buckets """
        self.assertEqual(self.routingTable._buckets[0].rangeMax, 2**384,
                             'Initial k-bucket range should be 0 <= range < 2**384')
        # Add k contacts
        for i in range(constants.k):
            node_id = generate_id(b'remote node %d' % i)
            contact = self.contact_manager.make_contact(node_id, '127.0.0.1', 9182, self.protocol)
            yield self.routingTable.addContact(contact)

        self.assertEqual(len(self.routingTable._buckets), 1,
                             'Only k nodes have been added; the first k-bucket should now '
                             'be full, but should not yet be split')
        # Now add 1 more contact
        node_id = generate_id(b'yet another remote node')
        contact = self.contact_manager.make_contact(node_id, '127.0.0.1', 9182, self.protocol)
        yield self.routingTable.addContact(contact)
        self.assertEqual(len(self.routingTable._buckets), 2,
                             'k+1 nodes have been added; the first k-bucket should have been '
                             'split into two new buckets')
        self.assertNotEqual(self.routingTable._buckets[0].rangeMax, 2**384,
                         'K-bucket was split, but its range was not properly adjusted')
        self.assertEqual(self.routingTable._buckets[1].rangeMax, 2**384,
                             'K-bucket was split, but the second (new) bucket\'s '
                             'max range was not set properly')
        self.assertEqual(self.routingTable._buckets[0].rangeMax,
                             self.routingTable._buckets[1].rangeMin,
                             'K-bucket was split, but the min/max ranges were '
                             'not divided properly')

    @defer.inlineCallbacks
    def test_full_split(self):
        """
        Test that a bucket is not split if it is full, but the new contact is not closer than the kth closest contact
        """

        self.routingTable._parentNodeID = bytes(48 * b'\xff')

        node_ids = [
            b"100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            b"200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            b"300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            b"400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            b"500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            b"600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            b"700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            b"800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            b"ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            b"010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]

        # Add k contacts
        for nodeID in node_ids:
            # self.assertEquals(nodeID, node_ids[i].decode('hex'))
            contact = self.contact_manager.make_contact(unhexlify(nodeID), '127.0.0.1', 9182, self.protocol)
            yield self.routingTable.addContact(contact)
        self.assertEqual(len(self.routingTable._buckets), 2)
        self.assertEqual(len(self.routingTable._buckets[0]._contacts), 8)
        self.assertEqual(len(self.routingTable._buckets[1]._contacts), 2)

        #  try adding a contact who is further from us than the k'th known contact
        nodeID = b'020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
        nodeID = unhexlify(nodeID)
        contact = self.contact_manager.make_contact(nodeID, '127.0.0.1', 9182, self.protocol)
        self.assertFalse(self.routingTable._shouldSplit(self.routingTable._kbucketIndex(contact.id), contact.id))
        yield self.routingTable.addContact(contact)
        self.assertEqual(len(self.routingTable._buckets), 2)
        self.assertEqual(len(self.routingTable._buckets[0]._contacts), 8)
        self.assertEqual(len(self.routingTable._buckets[1]._contacts), 2)
        self.assertFalse(contact in self.routingTable._buckets[0]._contacts)
        self.assertFalse(contact in self.routingTable._buckets[1]._contacts)
示例#13
0
class TreeRoutingTableTest(unittest.TestCase):
    """ Test case for the RoutingTable class """
    def setUp(self):
        h = hashlib.sha384()
        h.update('node1')
        self.contact_manager = ContactManager()
        self.nodeID = h.digest()
        self.protocol = FakeRPCProtocol()
        self.routingTable = TreeRoutingTable(self.nodeID)

    def testDistance(self):
        """ Test to see if distance method returns correct result"""

        # testList holds a couple 3-tuple (variable1, variable2, result)
        basicTestList = [(chr(170) * 48, chr(85) * 48,
                          long((chr(255) * 48).encode('hex'), 16))]

        for test in basicTestList:
            result = Distance(test[0])(test[1])
            self.failIf(
                result != test[2],
                'Result of _distance() should be %s but %s returned' %
                (test[2], result))

    @defer.inlineCallbacks
    def testAddContact(self):
        """ Tests if a contact can be added and retrieved correctly """
        # Create the contact
        h = hashlib.sha384()
        h.update('node2')
        contactID = h.digest()
        contact = self.contact_manager.make_contact(contactID, '127.0.0.1',
                                                    9182, self.protocol)
        # Now add it...
        yield self.routingTable.addContact(contact)
        # ...and request the closest nodes to it (will retrieve it)
        closestNodes = self.routingTable.findCloseNodes(contactID)
        self.failUnlessEqual(
            len(closestNodes), 1,
            'Wrong amount of contacts returned; expected 1,'
            ' got %d' % len(closestNodes))
        self.failUnless(
            contact in closestNodes, 'Added contact not found by issueing '
            '_findCloseNodes()')

    @defer.inlineCallbacks
    def testGetContact(self):
        """ Tests if a specific existing contact can be retrieved correctly """
        h = hashlib.sha384()
        h.update('node2')
        contactID = h.digest()
        contact = self.contact_manager.make_contact(contactID, '127.0.0.1',
                                                    9182, self.protocol)
        # Now add it...
        yield self.routingTable.addContact(contact)
        # ...and get it again
        sameContact = self.routingTable.getContact(contactID)
        self.failUnlessEqual(contact, sameContact,
                             'getContact() should return the same contact')

    @defer.inlineCallbacks
    def testAddParentNodeAsContact(self):
        """
        Tests the routing table's behaviour when attempting to add its parent node as a contact
        """

        # Create a contact with the same ID as the local node's ID
        contact = self.contact_manager.make_contact(self.nodeID, '127.0.0.1',
                                                    9182, self.protocol)
        # Now try to add it
        yield self.routingTable.addContact(contact)
        # ...and request the closest nodes to it using FIND_NODE
        closestNodes = self.routingTable.findCloseNodes(
            self.nodeID, constants.k)
        self.failIf(contact in closestNodes, 'Node added itself as a contact')

    @defer.inlineCallbacks
    def testRemoveContact(self):
        """ Tests contact removal """
        # Create the contact
        h = hashlib.sha384()
        h.update('node2')
        contactID = h.digest()
        contact = self.contact_manager.make_contact(contactID, '127.0.0.1',
                                                    9182, self.protocol)
        # Now add it...
        yield self.routingTable.addContact(contact)
        # Verify addition
        self.failUnlessEqual(len(self.routingTable._buckets[0]), 1,
                             'Contact not added properly')
        # Now remove it
        self.routingTable.removeContact(contact)
        self.failUnlessEqual(len(self.routingTable._buckets[0]), 0,
                             'Contact not removed properly')

    @defer.inlineCallbacks
    def testSplitBucket(self):
        """ Tests if the the routing table correctly dynamically splits k-buckets """
        self.failUnlessEqual(
            self.routingTable._buckets[0].rangeMax, 2**384,
            'Initial k-bucket range should be 0 <= range < 2**384')
        # Add k contacts
        for i in range(constants.k):
            h = hashlib.sha384()
            h.update('remote node %d' % i)
            nodeID = h.digest()
            contact = self.contact_manager.make_contact(
                nodeID, '127.0.0.1', 9182, self.protocol)
            yield self.routingTable.addContact(contact)
        self.failUnlessEqual(
            len(self.routingTable._buckets), 1,
            'Only k nodes have been added; the first k-bucket should now '
            'be full, but should not yet be split')
        # Now add 1 more contact
        h = hashlib.sha384()
        h.update('yet another remote node')
        nodeID = h.digest()
        contact = self.contact_manager.make_contact(nodeID, '127.0.0.1', 9182,
                                                    self.protocol)
        yield self.routingTable.addContact(contact)
        self.failUnlessEqual(
            len(self.routingTable._buckets), 2,
            'k+1 nodes have been added; the first k-bucket should have been '
            'split into two new buckets')
        self.failIfEqual(
            self.routingTable._buckets[0].rangeMax, 2**384,
            'K-bucket was split, but its range was not properly adjusted')
        self.failUnlessEqual(
            self.routingTable._buckets[1].rangeMax, 2**384,
            'K-bucket was split, but the second (new) bucket\'s '
            'max range was not set properly')
        self.failUnlessEqual(
            self.routingTable._buckets[0].rangeMax,
            self.routingTable._buckets[1].rangeMin,
            'K-bucket was split, but the min/max ranges were '
            'not divided properly')

    @defer.inlineCallbacks
    def testFullSplit(self):
        """
        Test that a bucket is not split if it is full, but the new contact is not closer than the kth closest contact
        """

        self.routingTable._parentNodeID = 48 * chr(255)

        node_ids = [
            "100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "ff0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
        ]

        # Add k contacts
        for nodeID in node_ids:
            # self.assertEquals(nodeID, node_ids[i].decode('hex'))
            contact = self.contact_manager.make_contact(
                nodeID.decode('hex'), '127.0.0.1', 9182, self.protocol)
            yield self.routingTable.addContact(contact)
        self.failUnlessEqual(len(self.routingTable._buckets), 2)
        self.failUnlessEqual(len(self.routingTable._buckets[0]._contacts), 8)
        self.failUnlessEqual(len(self.routingTable._buckets[1]._contacts), 2)

        #  try adding a contact who is further from us than the k'th known contact
        nodeID = '020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
        nodeID = nodeID.decode('hex')
        contact = self.contact_manager.make_contact(nodeID, '127.0.0.1', 9182,
                                                    self.protocol)
        self.assertFalse(
            self.routingTable._shouldSplit(
                self.routingTable._kbucketIndex(contact.id), contact.id))
        yield self.routingTable.addContact(contact)
        self.failUnlessEqual(len(self.routingTable._buckets), 2)
        self.failUnlessEqual(len(self.routingTable._buckets[0]._contacts), 8)
        self.failUnlessEqual(len(self.routingTable._buckets[1]._contacts), 2)
        self.failIf(contact in self.routingTable._buckets[0]._contacts)
        self.failIf(contact in self.routingTable._buckets[1]._contacts)
示例#14
0
class TestContactLastReplied(unittest.TestCase):
    def setUp(self):
        self.clock = task.Clock()
        self.contact_manager = ContactManager(self.clock.seconds)
        self.contact = self.contact_manager.make_contact(
            generate_id(), "127.0.0.1", 4444, None)
        self.clock.advance(3600)
        self.assertTrue(self.contact.contact_is_good is None)

    def test_stale_replied_to_us(self):
        self.contact.update_last_replied()
        self.assertTrue(self.contact.contact_is_good is True)

    def test_stale_requested_from_us(self):
        self.contact.update_last_requested()
        self.assertTrue(self.contact.contact_is_good is None)

    def test_stale_then_fail(self):
        self.contact.update_last_failed()
        self.assertTrue(self.contact.contact_is_good is None)
        self.clock.advance(1)
        self.contact.update_last_failed()
        self.assertTrue(self.contact.contact_is_good is False)

    def test_good_turned_stale(self):
        self.contact.update_last_replied()
        self.assertTrue(self.contact.contact_is_good is True)
        self.clock.advance(constants.checkRefreshInterval - 1)
        self.assertTrue(self.contact.contact_is_good is True)
        self.clock.advance(1)
        self.assertTrue(self.contact.contact_is_good is None)

    def test_good_then_fail(self):
        self.contact.update_last_replied()
        self.assertTrue(self.contact.contact_is_good is True)
        self.clock.advance(1)
        self.contact.update_last_failed()
        self.assertTrue(self.contact.contact_is_good is True)
        self.clock.advance(59)
        self.assertTrue(self.contact.contact_is_good is True)
        self.contact.update_last_failed()
        self.assertTrue(self.contact.contact_is_good is False)
        for _ in range(7200):
            self.clock.advance(60)
            self.assertTrue(self.contact.contact_is_good is False)

    def test_good_then_fail_then_good(self):
        # it replies
        self.contact.update_last_replied()
        self.assertTrue(self.contact.contact_is_good is True)
        self.clock.advance(1)

        # it fails twice in a row
        self.contact.update_last_failed()
        self.clock.advance(1)
        self.contact.update_last_failed()
        self.assertTrue(self.contact.contact_is_good is False)
        self.clock.advance(1)

        # it replies
        self.contact.update_last_replied()
        self.clock.advance(1)
        self.assertTrue(self.contact.contact_is_good is True)

        # it goes stale
        self.clock.advance(constants.checkRefreshInterval - 2)
        self.assertTrue(self.contact.contact_is_good is True)
        self.clock.advance(1)
        self.assertTrue(self.contact.contact_is_good is None)