2019-01-22 18:49:43 +01:00
|
|
|
import asyncio
|
|
|
|
import unittest
|
2019-06-21 03:02:58 +02:00
|
|
|
from lbry.utils import generate_id
|
2020-06-02 21:56:57 +02:00
|
|
|
from lbry.dht.peer import PeerManager, make_kademlia_peer, is_valid_public_ipv4
|
2019-12-31 21:30:13 +01:00
|
|
|
from lbry.testcase import AsyncioTestCase
|
2016-10-19 23:21:24 +02:00
|
|
|
|
|
|
|
|
2019-01-22 18:49:43 +01:00
|
|
|
class PeerTest(AsyncioTestCase):
|
2016-10-19 23:21:24 +02:00
|
|
|
def setUp(self):
|
2019-01-22 18:49:43 +01:00
|
|
|
self.loop = asyncio.get_event_loop()
|
|
|
|
self.peer_manager = PeerManager(self.loop)
|
2018-05-24 00:28:22 +02:00
|
|
|
self.node_ids = [generate_id(), generate_id(), generate_id()]
|
2019-11-29 21:28:41 +01:00
|
|
|
self.first_contact = make_kademlia_peer(self.node_ids[1], '1.0.0.1', udp_port=1000)
|
|
|
|
self.second_contact = make_kademlia_peer(self.node_ids[0], '1.0.0.2', udp_port=1000)
|
2018-05-24 00:28:22 +02:00
|
|
|
|
2019-10-01 23:11:30 +02:00
|
|
|
def test_peer_is_good_unknown_peer(self):
|
|
|
|
# Scenario: peer replied, but caller doesn't know the node_id.
|
|
|
|
# Outcome: We can't say it's good or bad.
|
|
|
|
# (yes, we COULD tell the node id, but not here. It would be
|
|
|
|
# a side effect and the caller is responsible to discover it)
|
|
|
|
peer = make_kademlia_peer(None, '1.2.3.4', 4444)
|
|
|
|
self.peer_manager.report_last_requested('1.2.3.4', 4444)
|
|
|
|
self.peer_manager.report_last_replied('1.2.3.4', 4444)
|
|
|
|
self.assertIsNone(self.peer_manager.peer_is_good(peer))
|
|
|
|
|
2018-07-31 19:20:25 +02:00
|
|
|
def test_make_contact_error_cases(self):
|
2019-11-29 21:28:41 +01:00
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '1.2.3.4', 100000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '1.2.3.4.5', 1000)
|
2019-10-01 02:00:10 +02:00
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], 'this is not an ip', 1000)
|
2019-11-29 21:28:41 +01:00
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '1.2.3.4', -1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '1.2.3.4', 0)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '1.2.3.4', 70000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, b'not valid node id', '1.2.3.4', 1000)
|
|
|
|
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '0.0.0.0', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '10.0.0.1', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '100.64.0.1', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '127.0.0.1', 1000)
|
|
|
|
self.assertIsNotNone(make_kademlia_peer(self.node_ids[1], '127.0.0.1', 1000, allow_localhost=True))
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '192.168.0.1', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '172.16.0.1', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '169.254.1.1', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '192.0.0.2', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '192.0.2.2', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '192.88.99.2', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '198.18.1.1', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '198.51.100.2', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '198.51.100.2', 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '203.0.113.4', 1000)
|
|
|
|
for i in range(32):
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], f"{224 + i}.0.0.0", 1000)
|
|
|
|
self.assertRaises(ValueError, make_kademlia_peer, self.node_ids[1], '255.255.255.255', 1000)
|
2020-06-02 21:56:57 +02:00
|
|
|
self.assertRaises(
|
|
|
|
ValueError, make_kademlia_peer, self.node_ids[1], 'beee:eeee:eeee:eeee:eeee:eeee:eeee:eeef', 1000
|
|
|
|
)
|
|
|
|
self.assertRaises(
|
|
|
|
ValueError, make_kademlia_peer, self.node_ids[1], '2001:db8::ff00:42:8329', 1000
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_is_valid_ipv4(self):
|
|
|
|
self.assertFalse(is_valid_public_ipv4('beee:eeee:eeee:eeee:eeee:eeee:eeee:eeef'))
|
|
|
|
self.assertFalse(is_valid_public_ipv4('beee:eeee:eeee:eeee:eeee:eeee:eeee:eeef', True))
|
|
|
|
|
|
|
|
self.assertFalse(is_valid_public_ipv4('2001:db8::ff00:42:8329'))
|
|
|
|
self.assertFalse(is_valid_public_ipv4('2001:db8::ff00:42:8329', True))
|
|
|
|
|
|
|
|
self.assertFalse(is_valid_public_ipv4('127.0.0.1'))
|
|
|
|
self.assertTrue(is_valid_public_ipv4('127.0.0.1', True))
|
|
|
|
|
|
|
|
self.assertFalse(is_valid_public_ipv4('172.16.0.1'))
|
|
|
|
self.assertFalse(is_valid_public_ipv4('172.16.0.1', True))
|
|
|
|
|
|
|
|
self.assertTrue(is_valid_public_ipv4('1.2.3.4'))
|
|
|
|
self.assertTrue(is_valid_public_ipv4('1.2.3.4', True))
|
|
|
|
|
|
|
|
self.assertFalse(is_valid_public_ipv4('derp'))
|
|
|
|
self.assertFalse(is_valid_public_ipv4('derp', True))
|
2018-07-31 19:20:25 +02:00
|
|
|
|
|
|
|
def test_boolean(self):
|
2019-01-22 18:49:43 +01:00
|
|
|
self.assertNotEqual(self.first_contact, self.second_contact)
|
|
|
|
self.assertEqual(
|
2019-11-29 21:28:41 +01:00
|
|
|
self.second_contact, make_kademlia_peer(self.node_ids[0], '1.0.0.2', udp_port=1000)
|
2018-08-22 06:12:46 +02:00
|
|
|
)
|
2016-10-19 23:21:24 +02:00
|
|
|
|
2018-07-31 19:20:25 +02:00
|
|
|
def test_compact_ip(self):
|
2019-11-29 21:28:41 +01:00
|
|
|
self.assertEqual(b'\x01\x00\x00\x01', self.first_contact.compact_ip())
|
|
|
|
self.assertEqual(b'\x01\x00\x00\x02', self.second_contact.compact_ip())
|
2018-07-31 19:20:25 +02:00
|
|
|
|
2018-05-24 00:31:31 +02:00
|
|
|
|
2019-01-22 18:49:43 +01:00
|
|
|
@unittest.SkipTest
|
2018-05-24 00:31:31 +02:00
|
|
|
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)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIsNone(self.contact.contact_is_good)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
def test_stale_replied_to_us(self):
|
|
|
|
self.contact.update_last_replied()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
def test_stale_requested_from_us(self):
|
|
|
|
self.contact.update_last_requested()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIsNone(self.contact.contact_is_good)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
def test_stale_then_fail(self):
|
|
|
|
self.contact.update_last_failed()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIsNone(self.contact.contact_is_good)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.clock.advance(1)
|
|
|
|
self.contact.update_last_failed()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, False)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
def test_good_turned_stale(self):
|
|
|
|
self.contact.update_last_replied()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-29 22:22:30 +02:00
|
|
|
self.clock.advance(constants.checkRefreshInterval - 1)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.clock.advance(1)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIsNone(self.contact.contact_is_good)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
def test_good_then_fail(self):
|
|
|
|
self.contact.update_last_replied()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.clock.advance(1)
|
|
|
|
self.contact.update_last_failed()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.clock.advance(59)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.contact.update_last_failed()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, False)
|
2018-05-24 00:31:31 +02:00
|
|
|
for _ in range(7200):
|
|
|
|
self.clock.advance(60)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, False)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
def test_good_then_fail_then_good(self):
|
|
|
|
# it replies
|
|
|
|
self.contact.update_last_replied()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.clock.advance(1)
|
|
|
|
|
|
|
|
# it fails twice in a row
|
|
|
|
self.contact.update_last_failed()
|
|
|
|
self.clock.advance(1)
|
|
|
|
self.contact.update_last_failed()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, False)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.clock.advance(1)
|
|
|
|
|
|
|
|
# it replies
|
|
|
|
self.contact.update_last_replied()
|
|
|
|
self.clock.advance(1)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
# it goes stale
|
2018-05-29 22:22:30 +02:00
|
|
|
self.clock.advance(constants.checkRefreshInterval - 2)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.clock.advance(1)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIsNone(self.contact.contact_is_good)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
|
2019-01-22 18:49:43 +01:00
|
|
|
@unittest.SkipTest
|
2018-05-24 00:31:31 +02:00
|
|
|
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)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIsNone(self.contact.contact_is_good)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
def test_previous_replied_then_requested(self):
|
|
|
|
# it requests
|
|
|
|
self.contact.update_last_requested()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
# it goes stale
|
2018-05-29 22:22:30 +02:00
|
|
|
self.clock.advance(constants.checkRefreshInterval - 1)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.clock.advance(1)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIsNone(self.contact.contact_is_good)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
def test_previous_replied_then_requested_then_failed(self):
|
|
|
|
# it requests
|
|
|
|
self.contact.update_last_requested()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, True)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.clock.advance(1)
|
|
|
|
|
|
|
|
# it fails twice in a row
|
|
|
|
self.contact.update_last_failed()
|
|
|
|
self.clock.advance(1)
|
|
|
|
self.contact.update_last_failed()
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, False)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.clock.advance(1)
|
|
|
|
|
|
|
|
# it requests
|
|
|
|
self.contact.update_last_requested()
|
|
|
|
self.clock.advance(1)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, False)
|
2018-05-24 00:31:31 +02:00
|
|
|
|
|
|
|
# it goes stale
|
|
|
|
self.clock.advance((constants.refreshTimeout / 4) - 2)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, False)
|
2018-05-24 00:31:31 +02:00
|
|
|
self.clock.advance(1)
|
2018-10-18 13:41:33 +02:00
|
|
|
self.assertIs(self.contact.contact_is_good, False)
|