diff --git a/protocol-testing/Cargo.lock b/protocol-testing/Cargo.lock index 950feda..732b4cf 100644 --- a/protocol-testing/Cargo.lock +++ b/protocol-testing/Cargo.lock @@ -5434,6 +5434,7 @@ dependencies = [ "serde_json", "serde_yaml", "similar", + "termsize", "tokio", "tracing", "tracing-subscriber 0.3.19", @@ -7209,6 +7210,16 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "termsize" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f11ff5c25c172608d5b85e2fb43ee9a6d683a7f4ab7f96ae07b3d8b590368fd" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "textwrap" version = "0.16.2" diff --git a/protocol-testing/Cargo.toml b/protocol-testing/Cargo.toml index 2864da7..c38f8f8 100644 --- a/protocol-testing/Cargo.toml +++ b/protocol-testing/Cargo.toml @@ -29,3 +29,4 @@ dotenv = "0.15.0" async-trait = "0.1.87" colored = "3.0.0" similar = "2.7.0" +termsize = "0.1.9" diff --git a/protocol-testing/src/main.rs b/protocol-testing/src/main.rs index 77ac316..0eb88bf 100644 --- a/protocol-testing/src/main.rs +++ b/protocol-testing/src/main.rs @@ -25,6 +25,10 @@ struct Args { #[arg(long, required_unless_present = "package", conflicts_with = "package")] package_path: Option, + /// If provided, only run the tests with a matching name + #[arg(long)] + match_test: Option, + /// Enable tycho logs #[arg(long, default_value_t = true)] tycho_logs: bool, @@ -56,8 +60,13 @@ fn main() -> miette::Result<()> { let args = Args::parse(); - let test_runner = - TestRunner::new(args.package_path()?, args.tycho_logs, args.db_url, args.vm_traces); + let test_runner = TestRunner::new( + args.package_path()?, + args.match_test, + args.tycho_logs, + args.db_url, + args.vm_traces, + ); test_runner.run_tests() } diff --git a/protocol-testing/src/test_runner.rs b/protocol-testing/src/test_runner.rs index f1c2d8c..13bb82e 100644 --- a/protocol-testing/src/test_runner.rs +++ b/protocol-testing/src/test_runner.rs @@ -8,7 +8,7 @@ use figment::{ use miette::{miette, IntoDiagnostic, WrapErr}; use postgres::{Client, Error, NoTls}; use tokio::runtime::Runtime; -use tracing::{debug, info}; +use tracing::{debug, error, info}; use tycho_client::feed::BlockHeader; use tycho_common::{ dto::{Chain, ProtocolComponent, ResponseAccount, ResponseProtocolState}, @@ -43,15 +43,29 @@ pub struct TestRunner { vm_traces: bool, substreams_path: PathBuf, adapter_contract_builder: AdapterContractBuilder, + match_test: Option, } impl TestRunner { - pub fn new(substreams_path: PathBuf, tycho_logs: bool, db_url: String, vm_traces: bool) -> Self { + pub fn new( + substreams_path: PathBuf, + match_test: Option, + tycho_logs: bool, + db_url: String, + vm_traces: bool, + ) -> Self { let repo_root = env::current_dir().expect("Failed to get current directory"); let evm_path = repo_root.join("../evm"); let adapter_contract_builder = AdapterContractBuilder::new(evm_path.to_string_lossy().to_string()); - Self { tycho_logs, db_url, vm_traces, substreams_path, adapter_contract_builder } + Self { + tycho_logs, + db_url, + vm_traces, + substreams_path, + adapter_contract_builder, + match_test, + } } pub fn run_tests(&self) -> miette::Result<()> { @@ -60,42 +74,45 @@ impl TestRunner { .join("integration_test.tycho.yaml"); let config = Self::parse_config(&config_yaml_path)?; + let terminal_width = termsize::get() + .map(|size| size.cols as usize - 35) // Remove length of log prefix + .unwrap_or(80); info!("Running {} tests ...\n", config.tests.len()); - info!("--------------------------------\n"); + info!("{}\n", "-".repeat(terminal_width)); let mut failed_tests: Vec = Vec::new(); let mut count = 1; for test in &config.tests { info!("TEST {}: {}", count, test.name); + if let Some(match_test) = &self.match_test { + if !test.name.contains(match_test) { + info!("Skipping test (does not match filter: {match_test})\n"); + count += 1; + continue; + } + } match self.run_test(test, &config, config.skip_balance_check) { Ok(_) => { - info!("\n✅ {} passed.\n", test.name); + info!("✅ {} passed\n", test.name); } Err(e) => { failed_tests.push(test.name.clone()); - info!("\n❗️ {} failed: {}\n", test.name, e); + error!("❗️{} failed: {}\n", test.name, e); } } - info!("--------------------------------\n"); + info!("{}\n", "-".repeat(terminal_width)); count += 1; } - info!( - "\nTests finished! \nRESULTS: {}/{} passed.\n", - config.tests.len() - failed_tests.len(), - config.tests.len() - ); + info!("Tests finished!"); + info!("Passed {}/{}", config.tests.len() - failed_tests.len(), config.tests.len()); if !failed_tests.is_empty() { - info!("Failed tests:"); - for failed_test in &failed_tests { - info!("- {}", failed_test); - } + error!("Failed: {}", failed_tests.join(", ")); } - info!("\n"); Ok(()) } @@ -402,7 +419,7 @@ fn validate_state( } } - info!("\n✅ Simulation validation passed.\n"); + info!("✅ Simulation validation passed"); Ok(()) }