test-utils: add crate::rpc::data module (#231)
Some checks failed
Audit / audit (push) Has been cancelled
CI / fmt (push) Has been cancelled
CI / typo (push) Has been cancelled
CI / ci (macos-latest, stable, bash) (push) Has been cancelled
CI / ci (ubuntu-latest, stable, bash) (push) Has been cancelled
CI / ci (windows-latest, stable-x86_64-pc-windows-gnu, msys2 {0}) (push) Has been cancelled
Deny / audit (push) Has been cancelled
Doc / build (push) Has been cancelled
Doc / deploy (push) Has been cancelled

* test-utils: add `crate::rpc::types` module

* test-utils: conditional json doc-tests

* json: add test data, fix macro doc tests

* json: add all data

* other: add all data

* bin: add skeleton

* docs

* move type to correct file

* rpc: `client/{client,constants}.rs` -> `client.rs`

* lib.rs: remove `clippy::module_inception`
This commit is contained in:
hinto-janai 2024-07-18 19:50:27 -04:00 committed by GitHub
parent 0a88ea13fc
commit aa718e224f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 2400 additions and 49 deletions

1
Cargo.lock generated
View file

@ -785,6 +785,7 @@ dependencies = [
"hex", "hex",
"hex-literal", "hex-literal",
"monero-serai", "monero-serai",
"paste",
"pretty_assertions", "pretty_assertions",
"serde", "serde",
"serde_json", "serde_json",

View file

@ -1,30 +1,30 @@
[package] [package]
name = "cuprate-test-utils" name = "cuprate-test-utils"
version = "0.1.0" version = "0.1.0"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
authors = ["Boog900", "hinto-janai"] authors = ["Boog900", "hinto-janai"]
[dependencies] [dependencies]
cuprate-types = { path = "../types" } cuprate-types = { path = "../types" }
cuprate-helper = { path = "../helper", features = ["map"] } cuprate-helper = { path = "../helper", features = ["map"] }
cuprate-wire = { path = "../net/wire" } cuprate-wire = { path = "../net/wire" }
cuprate-p2p-core = { path = "../p2p/p2p-core", features = ["borsh"] } cuprate-p2p-core = { path = "../p2p/p2p-core", features = ["borsh"] }
hex = { workspace = true } hex = { workspace = true }
hex-literal = { workspace = true } hex-literal = { workspace = true }
monero-serai = { workspace = true, features = ["std", "http-rpc"] } monero-serai = { workspace = true, features = ["std", "http-rpc"] }
futures = { workspace = true, features = ["std"] } futures = { workspace = true, features = ["std"] }
async-trait = { workspace = true } async-trait = { workspace = true }
tokio = { workspace = true, features = ["full"] } tokio = { workspace = true, features = ["full"] }
tokio-util = { workspace = true } tokio-util = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
bytes = { workspace = true, features = ["std"] } bytes = { workspace = true, features = ["std"] }
tempfile = { workspace = true } tempfile = { workspace = true }
paste = { workspace = true }
borsh = { workspace = true, features = ["derive"]} borsh = { workspace = true, features = ["derive"]}
[dev-dependencies] [dev-dependencies]
hex = { workspace = true } hex = { workspace = true }
pretty_assertions = { workspace = true } pretty_assertions = { workspace = true }

View file

@ -7,3 +7,4 @@ It currently contains:
- Code to spawn monerod instances and a testing network zone - Code to spawn monerod instances and a testing network zone
- Real raw and typed Monero data, e.g. `Block, Transaction` - Real raw and typed Monero data, e.g. `Block, Transaction`
- An RPC client to generate types from `cuprate_types` - An RPC client to generate types from `cuprate_types`
- Raw RPC request/response strings and binary data

View file

@ -292,7 +292,7 @@ mod tests {
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use crate::rpc::HttpRpcClient; use crate::rpc::client::HttpRpcClient;
/// Assert the defined blocks are the same compared to ones received from a local RPC call. /// Assert the defined blocks are the same compared to ones received from a local RPC call.
#[ignore] // FIXME: doesn't work in CI, we need a real unrestricted node #[ignore] // FIXME: doesn't work in CI, we need a real unrestricted node

View file

@ -12,7 +12,9 @@ use monero_serai::{
use cuprate_types::{VerifiedBlockInformation, VerifiedTransactionInformation}; use cuprate_types::{VerifiedBlockInformation, VerifiedTransactionInformation};
use crate::rpc::constants::LOCALHOST_RPC_URL; //---------------------------------------------------------------------------------------------------- Constants
/// The default URL used for Monero RPC connections.
pub const LOCALHOST_RPC_URL: &str = "http://127.0.0.1:18081";
//---------------------------------------------------------------------------------------------------- HttpRpcClient //---------------------------------------------------------------------------------------------------- HttpRpcClient
/// An HTTP RPC client for Monero. /// An HTTP RPC client for Monero.

View file

@ -1,7 +0,0 @@
//! RPC-related Constants.
//---------------------------------------------------------------------------------------------------- Use
//---------------------------------------------------------------------------------------------------- Constants
/// The default URL used for Monero RPC connections.
pub const LOCALHOST_RPC_URL: &str = "http://127.0.0.1:18081";

View file

@ -0,0 +1,55 @@
//! Binary data from [`.bin` endpoints](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_blocksbin).
//!
//! TODO: Not implemented yet.
//---------------------------------------------------------------------------------------------------- Import
use crate::rpc::data::macros::define_request_and_response;
//---------------------------------------------------------------------------------------------------- TODO
define_request_and_response! {
get_blocksbin,
GET_BLOCKS: &[u8],
Request = &[];
Response = &[];
}
define_request_and_response! {
get_blocks_by_heightbin,
GET_BLOCKS_BY_HEIGHT: &[u8],
Request = &[];
Response = &[];
}
define_request_and_response! {
get_hashesbin,
GET_HASHES: &[u8],
Request = &[];
Response = &[];
}
define_request_and_response! {
get_o_indexesbin,
GET_O_INDEXES: &[u8],
Request = &[];
Response = &[];
}
define_request_and_response! {
get_outsbin,
GET_OUTS: &[u8],
Request = &[];
Response = &[];
}
define_request_and_response! {
get_transaction_pool_hashesbin,
GET_TRANSACTION_POOL_HASHES: &[u8],
Request = &[];
Response = &[];
}
//---------------------------------------------------------------------------------------------------- Tests
#[cfg(test)]
mod test {
// use super::*;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,168 @@
//! Macros.
//---------------------------------------------------------------------------------------------------- define_request_and_response
/// A template for generating the RPC request and response `const` data.
///
/// See the [`crate::json`] module for example usage.
///
/// # Macro internals
/// This macro uses:
/// - [`define_request_and_response_doc`]
/// - [`define_request_and_response_test`]
macro_rules! define_request_and_response {
(
// The markdown tag for Monero daemon RPC documentation. Not necessarily the endpoint.
//
// Adding `(json)` after this will trigger the macro to automatically
// add a `serde_json` test for the request/response data.
$monero_daemon_rpc_doc_link:ident $(($test:ident))?,
// The base name.
// Attributes added here will apply to _both_
// request and response types.
$( #[$attr:meta] )*
$name:ident: $type:ty,
// The request type (and any doc comments, derives, etc).
$( #[$request_attr:meta] )*
Request = $request:expr;
// The response type (and any doc comments, derives, etc).
$( #[$response_attr:meta] )*
Response = $response:expr;
) => { paste::paste! {
#[doc = $crate::rpc::data::macros::define_request_and_response_doc!(
"response" => [<$name:upper _RESPONSE>],
$monero_daemon_rpc_doc_link,
)]
///
$( #[$attr] )*
///
$( #[$request_attr] )*
///
$(
#[doc = $crate::rpc::data::macros::define_request_and_response_doc_test!([<$name:upper _REQUEST>], $test)]
)?
pub const [<$name:upper _REQUEST>]: $type = $request;
#[doc = $crate::rpc::data::macros::define_request_and_response_doc!(
"request" => [<$name:upper _REQUEST>],
$monero_daemon_rpc_doc_link,
)]
///
$( #[$attr] )*
///
$( #[$response_attr] )*
///
$(
#[doc = $crate::rpc::data::macros::define_request_and_response_doc_test!([<$name:upper _RESPONSE>], $test)]
)?
pub const [<$name:upper _RESPONSE>]: $type = $response;
}};
}
pub(super) use define_request_and_response;
//---------------------------------------------------------------------------------------------------- define_request_and_response_doc
/// Generate documentation for the types generated
/// by the [`define_request_and_response`] macro.
///
/// See it for more info on inputs.
macro_rules! define_request_and_response_doc {
(
// This labels the last `[request]` or `[response]`
// hyperlink in documentation. Input is either:
// - "request"
// - "response"
//
// Remember this is linking to the _other_ type,
// so if defining a `Request` type, input should
// be "response".
$request_or_response:literal => $request_or_response_type:ident,
$monero_daemon_rpc_doc_link:ident,
) => {
concat!(
"",
"[Documentation](",
"https://www.getmonero.org/resources/developer-guides/daemon-rpc.html",
"#",
stringify!($monero_daemon_rpc_doc_link),
"), [",
$request_or_response,
"](",
stringify!($request_or_response_type),
")."
)
};
}
pub(super) use define_request_and_response_doc;
//---------------------------------------------------------------------------------------------------- define_request_and_response_test
/// Generate documentation for the types generated
/// by the [`define_request_and_response`] macro.
///
/// See it for more info on inputs.
macro_rules! define_request_and_response_doc_test {
// `/json_rpc` doc test.
(
// The ident of the `const` request/response.
$name:ident,
json_rpc
) => {
concat!(
"```rust\n",
"use cuprate_test_utils::rpc::data::json::*;\n",
"use serde_json::{to_value, Value};\n",
"\n",
"let value = serde_json::from_str::<Value>(&",
stringify!($name),
").unwrap();\n",
"let Value::Object(map) = value else {\n",
" panic!();\n",
"};\n",
"\n",
r#"assert_eq!(map.get("jsonrpc").unwrap(), "2.0");"#,
"\n",
r#"map.get("id").unwrap();"#,
"\n\n",
r#"if map.get("method").is_some() {"#,
"\n",
r#" return;"#,
"\n",
"}\n",
"\n",
r#"if map.get("result").is_none() {"#,
"\n",
r#" map.get("error").unwrap();"#,
"\n",
"}\n",
"\n",
"```\n",
)
};
// Other JSON endpoint doc test.
(
$name:ident,
other
) => {
concat!(
"```rust\n",
"use cuprate_test_utils::rpc::data::other::*;\n",
"use serde_json::{to_value, Value};\n",
"\n",
"let value = serde_json::from_str::<Value>(&",
stringify!($name),
");\n",
"```\n",
)
};
// No doc test.
(
$name:ident,
$test:ident,
) => {
""
};
}
pub(super) use define_request_and_response_doc_test;

View file

@ -0,0 +1,18 @@
//! Monero RPC data.
//!
//! This module contains real `monerod` RPC requests/responses
//! as `const` [`str`]s and byte arrays (binary).
//!
//! The strings include the JSON-RPC 2.0 portions of the JSON.
//! - Tests exist within this crate that ensure the JSON is valid
//! - Tests exist within Cuprate's `rpc/` crates that ensure these strings (de)serialize as valid types
//!
//! # Determinism
//! Note that although both request/response data is defined,
//! they aren't necessarily tied to each other, i.e. the request
//! will not deterministically lead to the response.
pub mod bin;
pub mod json;
mod macros;
pub mod other;

File diff suppressed because one or more lines are too long

View file

@ -1,25 +1,6 @@
//! Monero RPC client. //! Monero RPC data & client.
//! //!
//! This module is a client for Monero RPC that maps the types //! This module has a `monerod` RPC [`client`] and some real request/response [`data`].
//! into the native types used by Cuprate found in `cuprate_types`.
//!
//! # Usage
//! ```rust,ignore
//! #[tokio::main]
//! async fn main() {
//! // Create RPC client.
//! let rpc = HttpRpcClient::new(None).await;
//!
//! // Collect 20 blocks.
//! let mut vec: Vec<VerifiedBlockInformation> = vec![];
//! for height in (3130269 - 20)..3130269 {
//! vec.push(rpc.get_verified_block_information(height).await);
//! }
//! }
//! ```
mod client; pub mod client;
pub use client::HttpRpcClient; pub mod data;
mod constants;
pub use constants::LOCALHOST_RPC_URL;

View file

@ -17,4 +17,5 @@ extend-ignore-identifiers-re = [
extend-exclude = [ extend-exclude = [
"/misc/gpg_keys/", "/misc/gpg_keys/",
"cryptonight/", "cryptonight/",
"/test-utils/src/rpc/data/json.rs",
] ]