コード例 #1
0
    def test_on_block_received(self):
        # first test receiving a block we have no outstanding request for
        fake_block = asynctest.MagicMock()
        fake_block.index = 1
        fake_block.__len__.return_value = 50
        self.assertEqual(
            -1,
            self.syncmgr.on_block_received(from_nodeid=123, block=fake_block))

        # next test receiving a block that we DO have an outstanding request for, but not from the node that is now
        # delivering the block
        request_info = convenience.RequestInfo(height=1)
        request_info.add_new_flight(
            convenience.FlightInfo(node_id=456, height=1))
        self.syncmgr.block_requests[1] = request_info
        self.assertEqual(
            -2,
            self.syncmgr.on_block_received(from_nodeid=123, block=fake_block))
        self.assertEqual(request_info,
                         self.syncmgr.block_requests.get(1, None))

        # next test a valid scenario (outstanding request and receiving a block from the right node)
        mocked_node = node.NeoNode(object())
        mocked_node.nodeweight.append_new_speed = asynctest.MagicMock()
        mocked_node.nodeid = 456
        self.nodemgr.nodes = [mocked_node]
        self.syncmgr.on_block_received(from_nodeid=456, block=fake_block)
        mocked_node.nodeweight.append_new_speed.assert_called_once()
        self.assertIn(fake_block, self.syncmgr.block_cache)
        self.assertEqual(1, len(self.syncmgr.block_cache))

        # and finally try again for the same block and ensure it was not added again to the cache
        self.syncmgr.on_block_received(from_nodeid=456, block=fake_block)
        self.assertEqual(1, len(self.syncmgr.block_cache))
コード例 #2
0
 def test_get_least_failed_node3(self):
     # should not return a node that is in the process of disconnecting but does have the correct height
     self.node1.best_height = 10
     self.node1.disconnecting = True
     self.nodemgr.nodes = [self.node1, self.node2]
     ri = convenience.RequestInfo(height=10)
     self.assertEqual(None, self.nodemgr.get_least_failed_node(ri))
コード例 #3
0
 def test_get_least_failed_node1(self):
     # should return None if none of the nodes have the requested height
     self.node1.best_height = 0
     self.node2.best_height = 0
     # setup node manager
     self.nodemgr.nodes = [self.node1, self.node2]
     ri = convenience.RequestInfo(height=10)
     self.assertEqual(None, self.nodemgr.get_least_failed_node(ri))
コード例 #4
0
ファイル: test_various.py プロジェクト: simplitech/neo-mamba
    def test_most_recent_flight(self):
        ri = convenience.RequestInfo(0)
        self.assertIsNone(ri.most_recent_flight())

        fi = convenience.FlightInfo(1, 0)
        ri.add_new_flight(fi)
        most_recent = ri.most_recent_flight()
        self.assertEqual(ri.last_used_node, fi.node_id)
コード例 #5
0
ファイル: test_various.py プロジェクト: simplitech/neo-mamba
    def test_mark_failed(self):
        ri = convenience.RequestInfo(0)
        self.assertEqual(0, ri.failed_total)
        self.assertEqual(0, len(ri.failed_nodes))

        ri.mark_failed_node(123)
        self.assertEqual(1, ri.failed_total)
        self.assertEqual(1, len(ri.failed_nodes))
コード例 #6
0
    async def test_no_flights_timedout(self):
        target_height = 1
        request_info = convenience.RequestInfo(target_height)
        request_info.add_new_flight(
            convenience.FlightInfo(node_id=123, height=target_height))
        self.syncmgr.block_requests[1] = request_info

        # a recently recreated flight should not have timed out
        self.assertEqual(-2, await self.syncmgr._check_timeout())
コード例 #7
0
    def _add_block_flight_info(self, nodeid, height: int) -> None:
        request_info = self.block_requests.get(height, None)

        if request_info is None:
            # no outstanding requests for this particular height, so we create it
            req = convenience.RequestInfo(height)
            req.add_new_flight(convenience.FlightInfo(nodeid, height))
            self.block_requests[height] = req
        else:
            request_info.flights.update(
                {nodeid: convenience.FlightInfo(nodeid, height)})
コード例 #8
0
    def test_get_least_failed_node2(self):
        # should return the node with the lowest fail count for the request
        # for this test we setup that node1 has failed before, whereas node2 hasn't
        self.node1.best_height = 10
        self.node2.best_height = 10

        ri = convenience.RequestInfo(height=1)
        # pretend node 1 has already failed once for this request
        ri.failed_nodes[self.node1.nodeid] = 1

        # setup node manager
        self.nodemgr.nodes = [self.node1, self.node2]
        self.assertEqual(self.node2, self.nodemgr.get_least_failed_node(ri))
コード例 #9
0
    async def test_flights_timed_out(self):
        # scenario: have 2 outstanding flights that timed out
        # - 1 flight for a request that is still is not completed
        # - 1 flight has been made obsolete by a secondary for the same request_info and is still in cache waiting to be processed

        # construct flight 1 - request not yet satisfied
        target_height = 2
        node1_id = 123
        request_info = convenience.RequestInfo(target_height)
        request_info.mark_failed_node = asynctest.MagicMock()
        flight_info = convenience.FlightInfo(node_id=node1_id,
                                             height=target_height)
        # reduce start time to enforce exceeding timeout treshold
        flight_info.start_time -= self.syncmgr.BLOCK_REQUEST_TIMEOUT + 1
        request_info.add_new_flight(flight_info)
        self.syncmgr.block_requests[target_height] = request_info

        # construct flight 2 - request already satisfied
        target_height2 = 1
        node2_id = 456
        request_info2 = convenience.RequestInfo(target_height2)
        flight_info2 = convenience.FlightInfo(node_id=node2_id,
                                              height=target_height2)
        flight_info2.start_time -= self.syncmgr.BLOCK_REQUEST_TIMEOUT + 1
        request_info2.add_new_flight(flight_info2)
        self.syncmgr.block_requests[target_height2] = request_info2

        # we patch '_get_best_stored_block_height' to return `target_height2` as a way of saying;
        # either the chain or cache already has the data for this height
        with asynctest.patch.object(self.syncmgr,
                                    '_get_best_stored_block_height',
                                    return_value=target_height2):
            with asynctest.patch.object(self.nodemgr,
                                        'increase_node_timeout_count'
                                        ) as nodemgr_increase_timeout_count:
                result = await self.syncmgr._check_timeout()

        request_info.mark_failed_node.assert_called_with(node1_id)
        # both nodes had a flight that timed out
        nodemgr_increase_timeout_count.assert_has_calls(
            [asynctest.mock.call(node1_id),
             asynctest.mock.call(node2_id)],
            any_order=True)
        # the first time we call it we no longer have any connected nodes, so we can't request from anyone anymore
        self.assertEqual(-3, result)

        # now we "connect" a new node
        mock_node = node.NeoNode(protocol=object())
        mock_node.best_height = 10
        mock_node_id = 789
        mock_node.nodeid = mock_node_id
        mock_node.request_block_data = asynctest.CoroutineMock()
        self.nodemgr.nodes = [mock_node]
        # and try again
        with self.assertLogs(network_logger, 'DEBUG') as log_context:
            with asynctest.patch.object(self.syncmgr,
                                        '_get_best_stored_block_height',
                                        return_value=target_height2):
                with asynctest.patch.object(self.nodemgr,
                                            'increase_node_timeout_count'):
                    await self.syncmgr._check_timeout()

        # and validate that a new data request is sent
        self.assertIn("Block timeout for blocks 2 - 2", log_context.output[0])
        mock_node.request_block_data.assert_awaited_once_with(count=1,
                                                              index_start=2)
        # and also a new flight was added for the new node
        flight = request_info.most_recent_flight()
        self.assertEqual(mock_node_id, flight.node_id)

        # just for coverage
        flight.reset_start_time()
        self.assertTrue(
            datetime.utcnow().timestamp() - flight.start_time < 0.1)