change(tests): adds RPC request client for condensing shared code (#5619)

* Adds RPCRequestClient

* uses RPCRequestClient in the rest of the rpc calls

* removes duplicate expect call

* fixed mistaken "get_info" method call with "getinfo"

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
Arya 2022-11-16 16:23:29 -05:00 committed by GitHub
parent 816d845d94
commit 61af406d35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 75 additions and 74 deletions

View File

@ -161,6 +161,8 @@ use common::{
test_type::TestType::{self, *}, 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. /// 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. /// 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. /// Set `parallel_cpu_threads` to true to auto-configure based on the number of CPU cores.
#[tracing::instrument] #[tracing::instrument]
async fn rpc_endpoint(parallel_cpu_threads: bool) -> Result<()> { async fn rpc_endpoint(parallel_cpu_threads: bool) -> Result<()> {
use hyper::{body::to_bytes, Body, Client, Method, Request};
use serde_json::Value; use serde_json::Value;
let _init_guard = zebra_test::init(); 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 // Write a configuration that has RPC listen_addr set
// [Note on port conflict](#Note on port conflict) // [Note on port conflict](#Note on port conflict)
let mut config = random_known_rpc_port_config(parallel_cpu_threads)?; 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 dir = testdir()?.with_config(&mut config)?;
let mut child = dir.spawn_child(args!["start"])?; 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 // Create an http client
let client = Client::new(); let client = RPCRequestClient::new(config.rpc.listen_addr.unwrap());
// Create a request to call `getinfo` RPC method // Make the call to the `getinfo` RPC method
let req = Request::builder() let res = client.call("getinfo", "[]".to_string()).await?;
.method(Method::POST)
.uri(url)
.header("content-type", "application/json")
.body(Body::from(
r#"{"jsonrpc":"1.0","method":"getinfo","params":[],"id":123}"#,
))?;
// Make the call to the RPC endpoint
let res = client.request(req).await?;
// Test rpc endpoint response // Test rpc endpoint response
assert!(res.status().is_success()); 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 (body, mut child) = child.kill_on_error(body)?;
let parsed: Value = serde_json::from_slice(&body)?; let parsed: Value = serde_json::from_slice(&body)?;
@ -1419,17 +1410,12 @@ fn non_blocking_logger() -> Result<()> {
)?; )?;
// Create an http client // 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, // 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. // fill the channel that tracing logs are queued onto, and drop logs rather than block execution.
for _ in 0..500 { for _ in 0..500 {
let res = client let res = client.call("getinfo", "[]".to_string()).await?;
.post(format!("http://{}", &zebra_rpc_address))
.body(r#"{"jsonrpc":"1.0","method":"getinfo","params":[],"id":123}"#)
.header("Content-Type", "application/json")
.send()
.await?;
// Test that zebrad rpc endpoint is still responding to requests // Test that zebrad rpc endpoint is still responding to requests
assert!(res.status().is_success()); assert!(res.status().is_success());
@ -2042,28 +2028,17 @@ async fn fully_synced_rpc_test() -> Result<()> {
return Ok(()); return Ok(());
}; };
zebrad.expect_stdout_line_matches(&format!( let zebra_rpc_address = zebra_rpc_address.expect("lightwalletd test must have RPC port");
"Opened RPC endpoint at {}",
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). // 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 // The block is before the mandatory checkpoint, so the checkpoint cached state can be used
// if desired. // if desired.
let client = reqwest::Client::new();
let res = client let res = client
.post(format!( .text_from_call("getblock", r#"["1180900", 0]"#.to_string())
"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()
.await?; .await?;
// Simple textual check to avoid fully parsing the response, for simplicity // Simple textual check to avoid fully parsing the response, for simplicity

View File

@ -9,8 +9,6 @@ use std::path::{Path, PathBuf};
use std::time::Duration; use std::time::Duration;
use reqwest::Client;
use color_eyre::eyre::{eyre, Result}; use color_eyre::eyre::{eyre, Result};
use tempfile::TempDir; use tempfile::TempDir;
use tokio::fs; use tokio::fs;
@ -26,6 +24,7 @@ use zebra_chain::{
use zebra_state::{ChainTipChange, LatestChainTip}; use zebra_state::{ChainTipChange, LatestChainTip};
use crate::common::config::testdir; use crate::common::config::testdir;
use crate::common::rpc_client::RPCRequestClient;
use zebra_state::MAX_BLOCK_REORG_HEIGHT; use zebra_state::MAX_BLOCK_REORG_HEIGHT;
@ -231,22 +230,11 @@ pub async fn get_raw_future_blocks(
)?; )?;
// Create an http client // Create an http client
let client = Client::new(); let rpc_client = RPCRequestClient::new(rpc_address);
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 blockchain_info: serde_json::Value = serde_json::from_str( let blockchain_info: serde_json::Value = serde_json::from_str(
&send_rpc_request("getblockchaininfo", "[]".to_string()) &rpc_client
.await? .text_from_call("getblockchaininfo", "[]".to_string())
.text()
.await?, .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) { 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( let raw_block: serde_json::Value = serde_json::from_str(
&send_rpc_request("getblock", format!(r#"["{block_height}", 0]"#)) &rpc_client
.await? .text_from_call("getblock", format!(r#"["{block_height}", 0]"#))
.text()
.await?, .await?,
)?; )?;

View File

@ -10,12 +10,12 @@
use color_eyre::eyre::{Context, Result}; use color_eyre::eyre::{Context, Result};
use reqwest::Client;
use zebra_chain::parameters::Network; use zebra_chain::parameters::Network;
use crate::common::{ use crate::common::{
cached_state::get_raw_future_blocks, cached_state::get_raw_future_blocks,
launch::{can_spawn_zebrad_for_rpc, spawn_zebrad_for_rpc}, launch::{can_spawn_zebrad_for_rpc, spawn_zebrad_for_rpc},
rpc_client::RPCRequestClient,
test_type::TestType, test_type::TestType,
}; };
@ -65,16 +65,11 @@ pub(crate) async fn run() -> Result<()> {
tracing::info!(?rpc_address, "zebrad opened its RPC port",); tracing::info!(?rpc_address, "zebrad opened its RPC port",);
// Create an http client // Create an http client
let client = Client::new(); let client = RPCRequestClient::new(rpc_address);
for raw_block in raw_blocks { for raw_block in raw_blocks {
let res = client let res = client
.post(format!("http://{}", &rpc_address)) .call("submitblock", format!(r#"["{raw_block}"]"#))
.body(format!(
r#"{{"jsonrpc": "2.0", "method": "submitblock", "params": ["{raw_block}"], "id":123 }}"#
))
.header("Content-Type", "application/json")
.send()
.await?; .await?;
assert!(res.status().is_success()); assert!(res.status().is_success());

View File

@ -13,6 +13,7 @@ use zebra_test::prelude::*;
use crate::common::{ use crate::common::{
launch::ZebradTestDirExt, launch::ZebradTestDirExt,
lightwalletd::wallet_grpc::{connect_to_lightwalletd, ChainSpec}, lightwalletd::wallet_grpc::{connect_to_lightwalletd, ChainSpec},
rpc_client::RPCRequestClient,
test_type::TestType, test_type::TestType,
}; };
@ -182,14 +183,9 @@ pub fn are_zebrad_and_lightwalletd_tips_synced(
let lightwalletd_tip_height = lightwalletd_tip_block.height; let lightwalletd_tip_height = lightwalletd_tip_block.height;
// Get the block tip from zebrad // Get the block tip from zebrad
let zebrad_json_rpc_client = reqwest::Client::new(); let client = RPCRequestClient::new(zebra_rpc_address);
let zebrad_blockchain_info = zebrad_json_rpc_client let zebrad_blockchain_info = client
.post(format!("http://{}", &zebra_rpc_address.to_string())) .text_from_call("getblockchaininfo", "[]".to_string())
.body(r#"{"jsonrpc": "2.0", "method": "getblockchaininfo", "params": [], "id":123 }"#)
.header("Content-Type", "application/json")
.send()
.await?
.text()
.await?; .await?;
let zebrad_blockchain_info: serde_json::Value = let zebrad_blockchain_info: serde_json::Value =
serde_json::from_str(&zebrad_blockchain_info)?; serde_json::from_str(&zebrad_blockchain_info)?;

View File

@ -17,5 +17,6 @@ pub mod failure_messages;
pub mod get_block_template_rpcs; pub mod get_block_template_rpcs;
pub mod launch; pub mod launch;
pub mod lightwalletd; pub mod lightwalletd;
pub mod rpc_client;
pub mod sync; pub mod sync;
pub mod test_type; pub mod test_type;

View File

@ -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<String>,
) -> reqwest::Result<reqwest::Response> {
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<String>,
) -> reqwest::Result<String> {
self.call(method, params).await?.text().await
}
}