Skip to content

Commit

Permalink
change(tests): adds RPC request client for condensing shared code (#5619
Browse files Browse the repository at this point in the history
)

* 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>
  • Loading branch information
arya2 and mergify[bot] authored Nov 16, 2022
1 parent 816d845 commit 61af406
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 74 deletions.
53 changes: 14 additions & 39 deletions zebrad/tests/acceptance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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();
Expand All @@ -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"])?;
Expand All @@ -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)?;
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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
Expand Down
25 changes: 6 additions & 19 deletions zebrad/tests/common/cached_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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?,
)?;

Expand All @@ -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?,
)?;

Expand Down
11 changes: 3 additions & 8 deletions zebrad/tests/common/get_block_template_rpcs/submit_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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());
Expand Down
12 changes: 4 additions & 8 deletions zebrad/tests/common/lightwalletd/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};

Expand Down Expand Up @@ -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)?;
Expand Down
1 change: 1 addition & 0 deletions zebrad/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
47 changes: 47 additions & 0 deletions zebrad/tests/common/rpc_client.rs
Original file line number Diff line number Diff line change
@@ -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
}
}

0 comments on commit 61af406

Please sign in to comment.