From e2a3527414b048eb1099f6114d6ebe52ae29f36c Mon Sep 17 00:00:00 2001 From: Georgios Konstantopoulos Date: Wed, 11 Feb 2026 12:56:16 -0500 Subject: [PATCH] test: add CLI integration tests for reth binary (#22069) Co-authored-by: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Co-authored-by: Amp --- Cargo.lock | 46 ++++++++++++++++++++++++--- bin/reth/Cargo.toml | 3 ++ bin/reth/tests/it/main.rs | 67 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 bin/reth/tests/it/main.rs diff --git a/Cargo.lock b/Cargo.lock index f2ad0b356c..727e32ef6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -295,7 +295,7 @@ checksum = "d2ccfe6d724ceabd5518350cfb34f17dd3a6c3cc33579eee94d98101d3a511ff" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-hardforks", + "alloy-hardforks 0.4.7", "alloy-op-hardforks", "alloy-primitives", "alloy-rpc-types-engine", @@ -324,6 +324,19 @@ dependencies = [ "serde_with", ] +[[package]] +name = "alloy-hardforks" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165210652f71dfc094b051602bafd691f506c54050a174b1cba18fb5ef706a3" +dependencies = [ + "alloy-chains", + "alloy-eip2124", + "alloy-primitives", + "auto_impl", + "dyn-clone", +] + [[package]] name = "alloy-hardforks" version = "0.4.7" @@ -404,6 +417,28 @@ dependencies = [ "serde", ] +[[package]] +name = "alloy-node-bindings" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ce6930ce52e43b0768dc99ceeff5cb9e673e8c9f87d926914cd028b2e3f7233" +dependencies = [ + "alloy-genesis", + "alloy-hardforks 0.2.13", + "alloy-network", + "alloy-primitives", + "alloy-signer", + "alloy-signer-local", + "k256", + "libc", + "rand 0.8.5", + "serde_json", + "tempfile", + "thiserror 2.0.18", + "tracing", + "url", +] + [[package]] name = "alloy-op-hardforks" version = "0.4.7" @@ -411,7 +446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6472c610150c4c4c15be9e1b964c9b78068f933bda25fb9cdf09b9ac2bb66f36" dependencies = [ "alloy-chains", - "alloy-hardforks", + "alloy-hardforks 0.4.7", "alloy-primitives", "auto_impl", ] @@ -7510,6 +7545,8 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7" name = "reth" version = "1.10.2" dependencies = [ + "alloy-node-bindings", + "alloy-provider", "alloy-rpc-types", "aquamarine", "backon", @@ -7543,6 +7580,7 @@ dependencies = [ "reth-tasks", "reth-transaction-pool", "tempfile", + "tokio", "tracing", ] @@ -8543,7 +8581,7 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-genesis", - "alloy-hardforks", + "alloy-hardforks 0.4.7", "alloy-primitives", "alloy-rlp", "arbitrary", @@ -8661,7 +8699,7 @@ name = "reth-ethereum-forks" version = "1.10.2" dependencies = [ "alloy-eip2124", - "alloy-hardforks", + "alloy-hardforks 0.4.7", "alloy-primitives", "arbitrary", "auto_impl", diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index c482eb802e..469fb4ca9c 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -68,8 +68,11 @@ aquamarine.workspace = true clap = { workspace = true, features = ["derive", "env"] } [dev-dependencies] +alloy-node-bindings = "1.6.3" +alloy-provider = { workspace = true, features = ["reqwest"] } backon.workspace = true tempfile.workspace = true +tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } [features] default = [ diff --git a/bin/reth/tests/it/main.rs b/bin/reth/tests/it/main.rs new file mode 100644 index 0000000000..dcba8ba5ba --- /dev/null +++ b/bin/reth/tests/it/main.rs @@ -0,0 +1,67 @@ +#![allow(missing_docs)] + +use std::process::Command; + +const RETH: &str = env!("CARGO_BIN_EXE_reth"); + +#[test] +fn help() { + let output = Command::new(RETH).arg("--help").output().unwrap(); + let stdout = String::from_utf8_lossy(&output.stdout); + assert!(output.status.success()); + assert!(stdout.contains("Usage"), "stdout: {stdout}"); + assert!(stdout.contains("node"), "stdout: {stdout}"); +} + +#[test] +fn version() { + let output = Command::new(RETH).arg("--version").output().unwrap(); + let stdout = String::from_utf8_lossy(&output.stdout); + assert!(output.status.success()); + assert!(stdout.to_lowercase().contains("reth"), "stdout: {stdout}"); +} + +#[test] +fn node_help() { + let output = Command::new(RETH).args(["node", "--help"]).output().unwrap(); + let stdout = String::from_utf8_lossy(&output.stdout); + assert!(output.status.success()); + assert!(stdout.contains("--dev"), "stdout: {stdout}"); + assert!(stdout.contains("--http"), "stdout: {stdout}"); +} + +#[test] +fn unknown_subcommand() { + let output = Command::new(RETH).arg("definitely-not-a-cmd").output().unwrap(); + assert!(!output.status.success()); +} + +#[test] +fn unknown_flag() { + let output = Command::new(RETH).args(["node", "--no-such-flag"]).output().unwrap(); + let stderr = String::from_utf8_lossy(&output.stderr); + assert!(!output.status.success()); + assert!(stderr.contains("--no-such-flag"), "stderr: {stderr}"); +} + +#[tokio::test] +async fn dev_node_eth_syncing() { + use alloy_node_bindings::Reth; + use alloy_provider::{Provider, ProviderBuilder}; + + let reth = Reth::at(RETH) + .dev() + .disable_discovery() + .args(["--max-outbound-peers", "0", "--max-inbound-peers", "0"]) + .spawn(); + + let provider = ProviderBuilder::new().connect_http(reth.endpoint().parse().unwrap()); + + // give the node a moment to fully initialize + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + + // eth_syncing should not fail on a dev node + let _syncing = provider.syncing().await.expect("eth_syncing failed"); +} + +const fn main() {}