Платформа кластерного тестирования

В этом документе предлагается среда кластерного тестирования (CTF). CTF — это тестовая система, позволяющая выполнять тесты на локальном внутрипроцессном кластере или на развернутом кластере.

Мотивация

Цель CTF — предоставить основу для написания тестов независимо от того, где и как развернут кластер. В этих тестах можно фиксировать регрессии, а тесты можно запускать на развернутых кластерах для проверки развертывания. В центре внимания этих тестов должны быть стабильность кластера, консенсус, отказоустойчивость, стабильность API.

Тесты должны проверять единственную ошибку или сценарий и должны быть написаны с наименьшим количеством внутренней сантехники, подвергаемой тестированию.

Обзор дизайна

Для тестов предоставляется точка входа, которая представляет собой структуру contact_info::ContactInfo, и уже профинансированная пара ключей.

Каждый узел в кластере настраивается с помощью validator::ValidatorConfig во время загрузки. Во время загрузки эта конфигурация указывает любую дополнительную конфигурацию кластера, необходимую для теста. Кластер должен загружаться с конфигурацией, когда он работает внутри процесса или в центре обработки данных.

После загрузки тест обнаружит кластер через точку входа сплетен и настроит любое поведение во время выполнения через валидатор RPC.

Тестовый интерфейс

Каждый тест CTF начинается с непрозрачной точки входа и финансируемой пары ключей. Тест не должен зависеть от того, как развернут кластер, и должен иметь возможность использовать все функции кластера через общедоступные интерфейсы.

use crate::contact_info::ContactInfo;
use solana_sdk::signature::{Keypair, Signer};
pub fn test_this_behavior(
    entry_point_info: &ContactInfo,
    funding_keypair: &Keypair,
    num_nodes: usize,
)

Обнаружение кластера

При запуске теста кластер уже установлен и полностью подключен. Тест может обнаружить большинство доступных узлов за несколько секунд.

use crate::gossip_service::discover_nodes;

// Discover the cluster over a few seconds.
let cluster_nodes = discover_nodes(&entry_point_info, num_nodes);

Конфигурация кластера

Чтобы включить определенные сценарии, кластер необходимо загрузить со специальными конфигурациями. Эти конфигурации можно зафиксировать в validator::ValidatorConfig.

Например:

let mut validator_config = ValidatorConfig::default();
let local = LocalCluster::new_with_config(
                num_nodes,
                10_000,
                100,
                &validator_config
                );

Как разработать новый тест

Например, есть ошибка, которая показывает, что кластер выходит из строя, когда он заполнен недействительными анонсированными узлами сплетен. Наша библиотека сплетен и протокол могут измениться, но кластер по-прежнему должен оставаться устойчивым к потокам недействительных объявленных узлов сплетен.

Настройте службу RPC:

let mut validator_config = ValidatorConfig::default();
validator_config.rpc_config.enable_rpc_gossip_push = true;
validator_config.rpc_config.enable_rpc_gossip_refresh_active_set = true;

Подключите RPC и напишите новый тест:

pub fn test_large_invalid_gossip_nodes(
    entry_point_info: &ContactInfo,
    funding_keypair: &Keypair,
    num_nodes: usize,
) {
    let cluster = discover_nodes(&entry_point_info, num_nodes);

    // Poison the cluster.
    let client = create_client(entry_point_info.client_facing_addr(), VALIDATOR_PORT_RANGE);
    for _ in 0..(num_nodes * 100) {
        client.gossip_push(
            cluster_info::invalid_contact_info()
        );
    }
    sleep(Durration::from_millis(1000));

    // Force refresh of the active set.
    for node in &cluster {
        let client = create_client(node.client_facing_addr(), VALIDATOR_PORT_RANGE);
        client.gossip_refresh_active_set();
    }

    // Verify that spends still work.
    verify_spends(&cluster);
}