diff --git a/zebrad/tests/acceptance.rs b/zebrad/tests/acceptance.rs index ae25f819041..03b5e55d1ab 100644 --- a/zebrad/tests/acceptance.rs +++ b/zebrad/tests/acceptance.rs @@ -161,6 +161,8 @@ use common::{ test_type::TestType::{self, *}, }; +use crate::common::rpc_client::RPCRequestClient; + /// The maximum amount of time that we allow the creation of a future to block the `tokio` executor. /// /// This should be larger than the amount of time between thread time slices on a busy test VM. @@ -1320,7 +1322,6 @@ async fn rpc_endpoint_parallel_threads() -> Result<()> { /// Set `parallel_cpu_threads` to true to auto-configure based on the number of CPU cores. #[tracing::instrument] async fn rpc_endpoint(parallel_cpu_threads: bool) -> Result<()> { - use hyper::{body::to_bytes, Body, Client, Method, Request}; use serde_json::Value; let _init_guard = zebra_test::init(); @@ -1331,7 +1332,6 @@ async fn rpc_endpoint(parallel_cpu_threads: bool) -> Result<()> { // Write a configuration that has RPC listen_addr set // [Note on port conflict](#Note on port conflict) let mut config = random_known_rpc_port_config(parallel_cpu_threads)?; - let url = format!("http://{}", config.rpc.listen_addr.unwrap()); let dir = testdir()?.with_config(&mut config)?; let mut child = dir.spawn_child(args!["start"])?; @@ -1342,24 +1342,15 @@ async fn rpc_endpoint(parallel_cpu_threads: bool) -> Result<()> { )?; // Create an http client - let client = Client::new(); - - // Create a request to call `getinfo` RPC method - let req = Request::builder() - .method(Method::POST) - .uri(url) - .header("content-type", "application/json") - .body(Body::from( - r#"{"jsonrpc":"1.0","method":"getinfo","params":[],"id":123}"#, - ))?; + let client = RPCRequestClient::new(config.rpc.listen_addr.unwrap()); - // Make the call to the RPC endpoint - let res = client.request(req).await?; + // Make the call to the `getinfo` RPC method + let res = client.call("getinfo", "[]".to_string()).await?; // Test rpc endpoint response assert!(res.status().is_success()); - let body = to_bytes(res).await; + let body = res.bytes().await; let (body, mut child) = child.kill_on_error(body)?; let parsed: Value = serde_json::from_slice(&body)?; @@ -1419,17 +1410,12 @@ fn non_blocking_logger() -> Result<()> { )?; // Create an http client - let client = reqwest::Client::new(); + let client = RPCRequestClient::new(zebra_rpc_address); // Most of Zebra's lines are 100-200 characters long, so 500 requests should print enough to fill the unix pipe, // fill the channel that tracing logs are queued onto, and drop logs rather than block execution. for _ in 0..500 { - let res = client - .post(format!("http://{}", &zebra_rpc_address)) - .body(r#"{"jsonrpc":"1.0","method":"getinfo","params":[],"id":123}"#) - .header("Content-Type", "application/json") - .send() - .await?; + let res = client.call("getinfo", "[]".to_string()).await?; // Test that zebrad rpc endpoint is still responding to requests assert!(res.status().is_success()); @@ -2042,28 +2028,17 @@ async fn fully_synced_rpc_test() -> Result<()> { return Ok(()); }; - zebrad.expect_stdout_line_matches(&format!( - "Opened RPC endpoint at {}", - zebra_rpc_address.expect("lightwalletd test must have RPC port"), - ))?; + let zebra_rpc_address = zebra_rpc_address.expect("lightwalletd test must have RPC port"); + + zebrad.expect_stdout_line_matches(&format!("Opened RPC endpoint at {zebra_rpc_address}"))?; + + let client = RPCRequestClient::new(zebra_rpc_address); // Make a getblock test that works only on synced node (high block number). // The block is before the mandatory checkpoint, so the checkpoint cached state can be used // if desired. - let client = reqwest::Client::new(); let res = client - .post(format!( - "http://{}", - &zebra_rpc_address - .expect("lightwalletd test must have RPC port") - .to_string() - )) - // Manually constructed request to avoid encoding it, for simplicity - .body(r#"{"jsonrpc": "2.0", "method": "getblock", "params": ["1180900", 0], "id":123 }"#) - .header("Content-Type", "application/json") - .send() - .await? - .text() + .text_from_call("getblock", r#"["1180900", 0]"#.to_string()) .await?; // Simple textual check to avoid fully parsing the response, for simplicity diff --git a/zebrad/tests/common/cached_state.rs b/zebrad/tests/common/cached_state.rs index ad70983f588..9e87c6d6abe 100644 --- a/zebrad/tests/common/cached_state.rs +++ b/zebrad/tests/common/cached_state.rs @@ -9,8 +9,6 @@ use std::path::{Path, PathBuf}; use std::time::Duration; -use reqwest::Client; - use color_eyre::eyre::{eyre, Result}; use tempfile::TempDir; use tokio::fs; @@ -26,6 +24,7 @@ use zebra_chain::{ use zebra_state::{ChainTipChange, LatestChainTip}; use crate::common::config::testdir; +use crate::common::rpc_client::RPCRequestClient; use zebra_state::MAX_BLOCK_REORG_HEIGHT; @@ -231,22 +230,11 @@ pub async fn get_raw_future_blocks( )?; // Create an http client - let client = Client::new(); - - let send_rpc_request = |method, params| { - client - .post(format!("http://{}", &rpc_address)) - .body(format!( - r#"{{"jsonrpc": "2.0", "method": "{method}", "params": {params}, "id":123 }}"# - )) - .header("Content-Type", "application/json") - .send() - }; + let rpc_client = RPCRequestClient::new(rpc_address); let blockchain_info: serde_json::Value = serde_json::from_str( - &send_rpc_request("getblockchaininfo", "[]".to_string()) - .await? - .text() + &rpc_client + .text_from_call("getblockchaininfo", "[]".to_string()) .await?, )?; @@ -266,9 +254,8 @@ pub async fn get_raw_future_blocks( for block_height in (0..max_num_blocks).map(|idx| idx + estimated_finalized_tip_height) { let raw_block: serde_json::Value = serde_json::from_str( - &send_rpc_request("getblock", format!(r#"["{block_height}", 0]"#)) - .await? - .text() + &rpc_client + .text_from_call("getblock", format!(r#"["{block_height}", 0]"#)) .await?, )?; diff --git a/zebrad/tests/common/get_block_template_rpcs/submit_block.rs b/zebrad/tests/common/get_block_template_rpcs/submit_block.rs index 657816dde0f..9d979bb93fa 100644 --- a/zebrad/tests/common/get_block_template_rpcs/submit_block.rs +++ b/zebrad/tests/common/get_block_template_rpcs/submit_block.rs @@ -10,12 +10,12 @@ use color_eyre::eyre::{Context, Result}; -use reqwest::Client; use zebra_chain::parameters::Network; use crate::common::{ cached_state::get_raw_future_blocks, launch::{can_spawn_zebrad_for_rpc, spawn_zebrad_for_rpc}, + rpc_client::RPCRequestClient, test_type::TestType, }; @@ -65,16 +65,11 @@ pub(crate) async fn run() -> Result<()> { tracing::info!(?rpc_address, "zebrad opened its RPC port",); // Create an http client - let client = Client::new(); + let client = RPCRequestClient::new(rpc_address); for raw_block in raw_blocks { let res = client - .post(format!("http://{}", &rpc_address)) - .body(format!( - r#"{{"jsonrpc": "2.0", "method": "submitblock", "params": ["{raw_block}"], "id":123 }}"# - )) - .header("Content-Type", "application/json") - .send() + .call("submitblock", format!(r#"["{raw_block}"]"#)) .await?; assert!(res.status().is_success()); diff --git a/zebrad/tests/common/lightwalletd/sync.rs b/zebrad/tests/common/lightwalletd/sync.rs index 82ebc031161..fa979b34be3 100644 --- a/zebrad/tests/common/lightwalletd/sync.rs +++ b/zebrad/tests/common/lightwalletd/sync.rs @@ -13,6 +13,7 @@ use zebra_test::prelude::*; use crate::common::{ launch::ZebradTestDirExt, lightwalletd::wallet_grpc::{connect_to_lightwalletd, ChainSpec}, + rpc_client::RPCRequestClient, test_type::TestType, }; @@ -182,14 +183,9 @@ pub fn are_zebrad_and_lightwalletd_tips_synced( let lightwalletd_tip_height = lightwalletd_tip_block.height; // Get the block tip from zebrad - let zebrad_json_rpc_client = reqwest::Client::new(); - let zebrad_blockchain_info = zebrad_json_rpc_client - .post(format!("http://{}", &zebra_rpc_address.to_string())) - .body(r#"{"jsonrpc": "2.0", "method": "getblockchaininfo", "params": [], "id":123 }"#) - .header("Content-Type", "application/json") - .send() - .await? - .text() + let client = RPCRequestClient::new(zebra_rpc_address); + let zebrad_blockchain_info = client + .text_from_call("getblockchaininfo", "[]".to_string()) .await?; let zebrad_blockchain_info: serde_json::Value = serde_json::from_str(&zebrad_blockchain_info)?; diff --git a/zebrad/tests/common/mod.rs b/zebrad/tests/common/mod.rs index a1ef1365cb4..cb143cf50f0 100644 --- a/zebrad/tests/common/mod.rs +++ b/zebrad/tests/common/mod.rs @@ -17,5 +17,6 @@ pub mod failure_messages; pub mod get_block_template_rpcs; pub mod launch; pub mod lightwalletd; +pub mod rpc_client; pub mod sync; pub mod test_type; diff --git a/zebrad/tests/common/rpc_client.rs b/zebrad/tests/common/rpc_client.rs new file mode 100644 index 00000000000..f825c93fcd4 --- /dev/null +++ b/zebrad/tests/common/rpc_client.rs @@ -0,0 +1,47 @@ +//! A client for calling Zebra's Json-RPC methods + +use std::net::SocketAddr; + +use reqwest::Client; + +/// An http client for making Json-RPC requests +pub struct RPCRequestClient { + client: Client, + rpc_address: SocketAddr, +} + +impl RPCRequestClient { + /// Creates new RPCRequestSender + pub fn new(rpc_address: SocketAddr) -> Self { + Self { + client: Client::new(), + rpc_address, + } + } + + /// Builds rpc request + pub async fn call( + &self, + method: &'static str, + params: impl Into, + ) -> reqwest::Result { + let params = params.into(); + self.client + .post(format!("http://{}", &self.rpc_address)) + .body(format!( + r#"{{"jsonrpc": "2.0", "method": "{method}", "params": {params}, "id":123 }}"# + )) + .header("Content-Type", "application/json") + .send() + .await + } + + /// Builds rpc request and gets text from response + pub async fn text_from_call( + &self, + method: &'static str, + params: impl Into, + ) -> reqwest::Result { + self.call(method, params).await?.text().await + } +}