zakura-rpc 5.0.0

The Zakura node's JSON Remote Procedure Call (JSON-RPC) interface. Internal crate, published to support cargo install zakura
//! Fixed test vectors for the RPC server.

// These tests call functions which can take unit arguments if some features aren't enabled.
#![allow(clippy::unit_arg)]

use std::net::{Ipv4Addr, SocketAddrV4};

use tokio::sync::watch;
use tower::buffer::Buffer;

use zakura_chain::{
    chain_sync_status::MockSyncStatus, chain_tip::NoChainTip, parameters::Network::*,
};
use zakura_network::address_book_peers::MockAddressBookPeers;
use zakura_node_services::BoxError;
use zakura_test::mock_service::MockService;

use super::super::*;

use config::rpc::Config;

/// Test that the JSON-RPC server spawns.
#[tokio::test]
async fn rpc_server_spawn_test() {
    rpc_server_spawn().await
}

/// Test if the RPC server will spawn on a randomly generated port.
#[tracing::instrument]
async fn rpc_server_spawn() {
    let _init_guard = zakura_test::init();

    let conf = Config {
        listen_addr: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, 0).into()),
        indexer_listen_addr: None,
        parallel_cpu_threads: 0,
        debug_force_finished_sync: false,
        cookie_dir: Default::default(),
        cookie_file_name: ".cookie".to_string(),
        enable_cookie_auth: false,
        max_response_body_size: Default::default(),
        tls: None,
    };

    let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
    let state: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
    let mut read_state: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
    let mut block_verifier_router: MockService<_, _, _, BoxError> =
        MockService::build().for_unit_tests();

    info!("spawning RPC server...");

    let (_tx, rx) = watch::channel(None);
    let (rpc_impl, _) = RpcImpl::new(
        Mainnet,
        Default::default(),
        false,
        "RPC test",
        "RPC test",
        Buffer::new(mempool.clone(), 1),
        Buffer::new(state.clone(), 1),
        Buffer::new(read_state.clone(), 1),
        Buffer::new(block_verifier_router.clone(), 1),
        MockSyncStatus::default(),
        NoChainTip,
        MockAddressBookPeers::default(),
        rx,
        None,
    );

    RpcServer::start(rpc_impl, conf)
        .await
        .expect("RPC server should start");

    info!("spawned RPC server, checking services...");

    tokio::join!(
        mempool.expect_no_requests(),
        read_state.expect_no_requests(),
        block_verifier_router.expect_no_requests(),
    );
}

/// Test that the JSON-RPC server spawns on an OS-assigned unallocated port.
#[tokio::test]
async fn rpc_server_spawn_unallocated_port() {
    rpc_spawn_unallocated_port(false).await
}

/// Test that the JSON-RPC server spawns and shuts down on an OS-assigned unallocated port.
#[tokio::test]
async fn rpc_server_spawn_unallocated_port_shutdown() {
    rpc_spawn_unallocated_port(true).await
}

/// Test if the RPC server will spawn on an OS-assigned unallocated port.
///
/// Set `do_shutdown` to true to close the server using the close handle.
#[tracing::instrument]
async fn rpc_spawn_unallocated_port(do_shutdown: bool) {
    let _init_guard = zakura_test::init();

    let port = zakura_test::net::random_unallocated_port();
    #[allow(unknown_lints)]
    #[allow(clippy::bool_to_int_with_if)]
    let conf = Config {
        listen_addr: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, port).into()),
        indexer_listen_addr: None,
        parallel_cpu_threads: 0,
        debug_force_finished_sync: false,
        cookie_dir: Default::default(),
        cookie_file_name: ".cookie".to_string(),
        enable_cookie_auth: false,
        max_response_body_size: Default::default(),
        tls: None,
    };

    let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
    let mut state: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
    let mut read_state: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
    let mut block_verifier_router: MockService<_, _, _, BoxError> =
        MockService::build().for_unit_tests();

    info!("spawning RPC server...");

    let (_tx, rx) = watch::channel(None);
    let (rpc_impl, _) = RpcImpl::new(
        Mainnet,
        Default::default(),
        false,
        "RPC test",
        "RPC test",
        Buffer::new(mempool.clone(), 1),
        Buffer::new(state.clone(), 1),
        Buffer::new(read_state.clone(), 1),
        Buffer::new(block_verifier_router.clone(), 1),
        MockSyncStatus::default(),
        NoChainTip,
        MockAddressBookPeers::default(),
        rx,
        None,
    );

    let rpc = RpcServer::start(rpc_impl, conf)
        .await
        .expect("server should start");

    info!("spawned RPC server, checking services...");

    tokio::join!(
        mempool.expect_no_requests(),
        state.expect_no_requests(),
        read_state.expect_no_requests(),
        block_verifier_router.expect_no_requests(),
    );

    if do_shutdown {
        rpc.abort();
    }
}

/// Test if the RPC server will panic correctly when there is a port conflict.
#[tokio::test]
async fn rpc_server_spawn_port_conflict() {
    let _init_guard = zakura_test::init();

    let port = zakura_test::net::random_known_port();
    let conf = Config {
        listen_addr: Some(SocketAddrV4::new(Ipv4Addr::LOCALHOST, port).into()),
        indexer_listen_addr: None,
        debug_force_finished_sync: false,
        parallel_cpu_threads: 0,
        cookie_dir: Default::default(),
        cookie_file_name: ".cookie".to_string(),
        enable_cookie_auth: false,
        max_response_body_size: Default::default(),
        tls: None,
    };

    let mut mempool: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
    let mut state: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
    let mut read_state: MockService<_, _, _, BoxError> = MockService::build().for_unit_tests();
    let mut block_verifier_router: MockService<_, _, _, BoxError> =
        MockService::build().for_unit_tests();

    let (_tx, rx) = watch::channel(None);
    let (rpc_impl, _) = RpcImpl::new(
        Mainnet,
        Default::default(),
        false,
        "RPC test",
        "RPC test",
        Buffer::new(mempool.clone(), 1),
        Buffer::new(state.clone(), 1),
        Buffer::new(read_state.clone(), 1),
        Buffer::new(block_verifier_router.clone(), 1),
        MockSyncStatus::default(),
        NoChainTip,
        MockAddressBookPeers::default(),
        rx.clone(),
        None,
    );

    RpcServer::start(rpc_impl.clone(), conf.clone())
        .await
        .expect("RPC server should start");

    RpcServer::start(rpc_impl, conf)
        .await
        .expect_err("RPC server should not start");

    tokio::join!(
        mempool.expect_no_requests(),
        state.expect_no_requests(),
        read_state.expect_no_requests(),
        block_verifier_router.expect_no_requests(),
    );
}