async def test_ping_handler_requests_updated_enr(ping_handler,
                                                 incoming_message_channels,
                                                 outgoing_message_channels,
                                                 local_enr, remote_enr,
                                                 routing_table):
    ping = PingMessageFactory(enr_seq=remote_enr.sequence_number + 1)
    incoming_message = IncomingMessageFactory(message=ping)
    await incoming_message_channels[0].send(incoming_message)

    await wait_all_tasks_blocked()
    first_outgoing_message = outgoing_message_channels[1].receive_nowait()
    await wait_all_tasks_blocked()
    second_outgoing_message = outgoing_message_channels[1].receive_nowait()

    assert {
        first_outgoing_message.message.__class__,
        second_outgoing_message.message.__class__,
    } == {PongMessage, FindNodeMessage}

    outgoing_find_node = (first_outgoing_message if isinstance(
        first_outgoing_message.message, FindNodeMessage) else
                          second_outgoing_message)

    assert outgoing_find_node.message.distance == 0
    assert outgoing_find_node.receiver_endpoint == incoming_message.sender_endpoint
    assert outgoing_find_node.receiver_node_id == incoming_message.sender_node_id
async def test_find_node_handler_sends_many_remote_enrs(find_node_handler_service,
                                                        incoming_message_channels,
                                                        outgoing_message_channels,
                                                        filled_routing_table,
                                                        node_db):
    distance = 255
    node_ids = filled_routing_table.get_nodes_at_log_distance(distance)
    assert len(node_ids) == filled_routing_table.bucket_size
    enrs = [node_db.get_enr(node_id) for node_id in node_ids]

    find_node = FindNodeMessageFactory(distance=distance)
    incoming_message = IncomingMessageFactory(message=find_node)
    await incoming_message_channels[0].send(incoming_message)

    outgoing_messages = []
    while True:
        await wait_all_tasks_blocked()
        try:
            outgoing_messages.append(outgoing_message_channels[1].receive_nowait())
        except trio.WouldBlock:
            break

    for outgoing_message in outgoing_messages:
        assert isinstance(outgoing_message.message, NodesMessage)
        assert outgoing_message.message.request_id == find_node.request_id
        assert outgoing_message.message.total == len(outgoing_messages)
        assert outgoing_message.message.enrs
    sent_enrs = [
        enr
        for outgoing_message in outgoing_messages
        for enr in outgoing_message.message.enrs
    ]
    assert sent_enrs == enrs
async def test_ping_handler_sends_pong(ping_handler, incoming_message_channels,
                                       outgoing_message_channels, local_enr):
    ping = PingMessageFactory()
    incoming_message = IncomingMessageFactory(message=ping)
    await incoming_message_channels[0].send(incoming_message)
    await wait_all_tasks_blocked()

    outgoing_message = outgoing_message_channels[1].receive_nowait()
    assert isinstance(outgoing_message.message, PongMessage)
    assert outgoing_message.message.request_id == ping.request_id
    assert outgoing_message.message.enr_seq == local_enr.sequence_number
    assert outgoing_message.receiver_endpoint == incoming_message.sender_endpoint
    assert outgoing_message.receiver_node_id == incoming_message.sender_node_id
async def test_find_node_handler_sends_nodes(find_node_handler,
                                             incoming_message_channels,
                                             outgoing_message_channels,
                                             local_enr):
    find_node = FindNodeMessageFactory(distance=0)
    incoming_message = IncomingMessageFactory(message=find_node)
    await incoming_message_channels[0].send(incoming_message)
    await wait_all_tasks_blocked()

    outgoing_message = outgoing_message_channels[1].receive_nowait()
    assert isinstance(outgoing_message.message, NodesMessage)
    assert outgoing_message.message.request_id == find_node.request_id
    assert outgoing_message.message.total == 1
    assert outgoing_message.message.enrs == (local_enr, )
async def test_ping_handler_updates_routing_table(ping_handler,
                                                  incoming_message_channels,
                                                  outgoing_message_channels,
                                                  local_enr, remote_enr,
                                                  routing_table):
    other_node_id = NodeIDFactory()
    routing_table.add(other_node_id)
    assert routing_table.get_oldest_entry() == remote_enr.node_id

    ping = PingMessageFactory()
    incoming_message = IncomingMessageFactory(
        message=ping,
        sender_node_id=remote_enr.node_id,
    )
    await incoming_message_channels[0].send(incoming_message)
    await wait_all_tasks_blocked()

    assert routing_table.get_oldest_entry() == other_node_id
async def test_find_node_handler_sends_empty(find_node_handler_service,
                                             incoming_message_channels,
                                             outgoing_message_channels,
                                             routing_table, node_db):
    distance = 5
    assert len(routing_table.get_nodes_at_log_distance(distance)) == 0

    find_node = FindNodeMessageFactory(distance=distance)
    incoming_message = IncomingMessageFactory(message=find_node)
    await incoming_message_channels[0].send(incoming_message)

    await wait_all_tasks_blocked()
    outgoing_message = outgoing_message_channels[1].receive_nowait()

    assert isinstance(outgoing_message.message, NodesMessage)
    assert outgoing_message.message.request_id == find_node.request_id
    assert outgoing_message.message.total == 1
    assert not outgoing_message.message.enrs
async def test_ping_handler_updates_routing_table(ping_handler_service,
                                                  incoming_message_channels,
                                                  outgoing_message_channels,
                                                  local_enr,
                                                  remote_enr,
                                                  routing_table):
    distance = compute_log_distance(remote_enr.node_id, local_enr.node_id)
    other_node_id = NodeIDFactory.at_log_distance(local_enr.node_id, distance)
    routing_table.update(other_node_id)
    assert routing_table.get_nodes_at_log_distance(distance) == (other_node_id, remote_enr.node_id)

    ping = PingMessageFactory()
    incoming_message = IncomingMessageFactory(
        message=ping,
        sender_node_id=remote_enr.node_id,
    )
    await incoming_message_channels[0].send(incoming_message)
    await wait_all_tasks_blocked()

    assert routing_table.get_nodes_at_log_distance(distance) == (remote_enr.node_id, other_node_id)