def test_get_nodes_at_log_distance(routing_table, center_node_id, bucket_size):
    nodes = tuple(NodeIDFactory.at_log_distance(center_node_id, 200) for _ in range(bucket_size))
    farther_nodes = tuple(NodeIDFactory.at_log_distance(center_node_id, 201) for _ in range(5))
    closer_nodes = tuple(NodeIDFactory.at_log_distance(center_node_id, 199) for _ in range(5))
    for node_id in nodes + farther_nodes + closer_nodes:
        routing_table.update(node_id)

    assert set(routing_table.get_nodes_at_log_distance(200)) == set(nodes)
def test_update(routing_table, center_node_id):
    node_id_1 = NodeIDFactory.at_log_distance(center_node_id, 200)
    node_id_2 = NodeIDFactory.at_log_distance(center_node_id, 200)
    routing_table.update(node_id_1)
    routing_table.update(node_id_2)
    assert routing_table.get_nodes_at_log_distance(200) == (node_id_2, node_id_1)
    routing_table.update(node_id_2)
    assert routing_table.get_nodes_at_log_distance(200) == (node_id_2, node_id_1)
    routing_table.update(node_id_1)
    assert routing_table.get_nodes_at_log_distance(200) == (node_id_1, node_id_2)
def test_iter_around(routing_table, center_node_id):
    reference_node_id = NodeIDFactory.at_log_distance(center_node_id, 100)
    node_ids = tuple(
        NodeIDFactory.at_log_distance(reference_node_id, distance)
        for distance in (1, 2, 100, 200)
    )
    for node_id in node_ids:
        routing_table.update(node_id)

    assert tuple(routing_table.iter_nodes_around(reference_node_id)) == node_ids
    assert tuple(routing_table.iter_nodes_around(node_ids[0])) == node_ids
    assert tuple(routing_table.iter_nodes_around(node_ids[-1])) != node_ids
def test_add(routing_table, center_node_id):
    assert routing_table.get_nodes_at_log_distance(255) == ()

    node_id_1 = NodeIDFactory.at_log_distance(center_node_id, 255)
    routing_table.update(node_id_1)
    assert routing_table.get_nodes_at_log_distance(255) == (node_id_1,)

    node_id_2 = NodeIDFactory.at_log_distance(center_node_id, 255)
    routing_table.update(node_id_2)
    assert routing_table.get_nodes_at_log_distance(255) == (node_id_2, node_id_1)

    node_id_3 = NodeIDFactory.at_log_distance(center_node_id, 255)
    routing_table.update(node_id_3)
    assert routing_table.get_nodes_at_log_distance(255) == (node_id_2, node_id_1)

    node_id_4 = NodeIDFactory.at_log_distance(center_node_id, 1)
    routing_table.update(node_id_4)
    assert routing_table.get_nodes_at_log_distance(1) == (node_id_4,)
def test_remove(routing_table, center_node_id):
    node_id_1 = NodeIDFactory.at_log_distance(center_node_id, 200)
    node_id_2 = NodeIDFactory.at_log_distance(center_node_id, 200)
    node_id_3 = NodeIDFactory.at_log_distance(center_node_id, 200)
    node_id_4 = NodeIDFactory.at_log_distance(center_node_id, 200)
    routing_table.update(node_id_1)
    routing_table.update(node_id_2)
    routing_table.update(node_id_3)
    routing_table.update(node_id_4)
    assert routing_table.get_nodes_at_log_distance(200) == (node_id_2, node_id_1)

    routing_table.remove(node_id_4)  # remove from replacement cache, shouldn't appear again
    routing_table.remove(node_id_2)
    assert routing_table.get_nodes_at_log_distance(200) == (node_id_1, node_id_3)
    routing_table.remove(node_id_3)
    assert routing_table.get_nodes_at_log_distance(200) == (node_id_1,)
    routing_table.remove(node_id_1)
    assert routing_table.get_nodes_at_log_distance(200) == ()
    routing_table.remove(node_id_1)  # shouldn't raise
def test_least_recently_updated_distance(routing_table, center_node_id):
    with pytest.raises(ValueError):
        routing_table.get_least_recently_updated_log_distance()

    node_id_1 = NodeIDFactory.at_log_distance(center_node_id, 200)
    routing_table.update(node_id_1)
    assert routing_table.get_least_recently_updated_log_distance() == 200

    node_id_2 = NodeIDFactory.at_log_distance(center_node_id, 100)
    routing_table.update(node_id_2)
    assert routing_table.get_least_recently_updated_log_distance() == 200
    routing_table.update(node_id_1)
    assert routing_table.get_least_recently_updated_log_distance() == 100

    routing_table.remove(node_id_1)
    assert routing_table.get_least_recently_updated_log_distance() == 100

    routing_table.remove(node_id_2)
    with pytest.raises(ValueError):
        routing_table.get_least_recently_updated_log_distance()
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)
def test_fill_bucket(routing_table, center_node_id, bucket_size):
    assert not routing_table.get_nodes_at_log_distance(200)
    for _ in range(2 * bucket_size):
        routing_table.update(NodeIDFactory.at_log_distance(center_node_id, 200))
    assert len(routing_table.get_nodes_at_log_distance(200)) == bucket_size