mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-05-29 21:21:02 +00:00
save before flight
This commit is contained in:
@@ -373,7 +373,7 @@ where
|
|||||||
if !expects_exception {
|
if !expects_exception {
|
||||||
return Err(err).context("Failed to handle the function call execution");
|
return Err(err).context("Failed to handle the function call execution");
|
||||||
}
|
}
|
||||||
tracing::info!("Transaction failed as expected: {err:?}");
|
tracing::info!("Transaction failed as expected");
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ use std::{
|
|||||||
io::{BufRead, BufReader, BufWriter, Write},
|
io::{BufRead, BufReader, BufWriter, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::Instant,
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use temp_dir::TempDir;
|
use temp_dir::TempDir;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
@@ -40,6 +40,10 @@ struct MlTestRunnerArgs {
|
|||||||
#[arg(long = "cached-passed")]
|
#[arg(long = "cached-passed")]
|
||||||
cached_passed: Option<PathBuf>,
|
cached_passed: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// File to store tests that have failed (defaults to .<platform>-failed)
|
||||||
|
#[arg(long = "cached-failed")]
|
||||||
|
cached_failed: Option<PathBuf>,
|
||||||
|
|
||||||
/// Stop after the first file failure
|
/// Stop after the first file failure
|
||||||
#[arg(long = "bail")]
|
#[arg(long = "bail")]
|
||||||
bail: bool,
|
bail: bool,
|
||||||
@@ -92,6 +96,40 @@ fn main() -> anyhow::Result<()> {
|
|||||||
.block_on(run(args))
|
.block_on(run(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wait for HTTP server to be ready by attempting to connect to the specified port
|
||||||
|
async fn wait_for_http_server(port: u16) -> anyhow::Result<()> {
|
||||||
|
const MAX_RETRIES: u32 = 60;
|
||||||
|
const RETRY_DELAY: Duration = Duration::from_secs(1);
|
||||||
|
|
||||||
|
for attempt in 1..=MAX_RETRIES {
|
||||||
|
match tokio::net::TcpStream::connect(format!("127.0.0.1:{}", port)).await {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("Successfully connected to HTTP server on port {} (attempt {})", port, attempt);
|
||||||
|
return Ok(());
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
if attempt == MAX_RETRIES {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Failed to connect to HTTP server on port {} after {} attempts: {}",
|
||||||
|
port,
|
||||||
|
MAX_RETRIES,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if attempt % 10 == 0 {
|
||||||
|
info!(
|
||||||
|
"Still waiting for HTTP server on port {} (attempt {}/{})",
|
||||||
|
port, attempt, MAX_RETRIES
|
||||||
|
);
|
||||||
|
}
|
||||||
|
tokio::time::sleep(RETRY_DELAY).await;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
|
|
||||||
@@ -109,6 +147,14 @@ async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let cached_passed = Arc::new(Mutex::new(cached_passed));
|
let cached_passed = Arc::new(Mutex::new(cached_passed));
|
||||||
|
|
||||||
|
// Set up cached-failed file (defaults to .<platform>-failed)
|
||||||
|
let cached_failed_path = args
|
||||||
|
.cached_failed
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| PathBuf::from(format!(".{:?}-failed", args.platform)));
|
||||||
|
|
||||||
|
let cached_failed = Arc::new(Mutex::new(HashSet::<String>::new()));
|
||||||
|
|
||||||
// Get the platform based on CLI args
|
// Get the platform based on CLI args
|
||||||
let platform: &dyn Platform = match args.platform {
|
let platform: &dyn Platform = match args.platform {
|
||||||
PlatformIdentifier::GethEvmSolc => &revive_dt_core::GethEvmSolcPlatform,
|
PlatformIdentifier::GethEvmSolc => &revive_dt_core::GethEvmSolcPlatform,
|
||||||
@@ -147,7 +193,13 @@ async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
|||||||
|
|
||||||
node
|
node
|
||||||
} else {
|
} else {
|
||||||
info!("Using existing node");
|
info!("Using existing node at port {}", args.rpc_port);
|
||||||
|
|
||||||
|
// Wait for the HTTP server to be ready
|
||||||
|
info!("Waiting for HTTP server to be ready on port {}...", args.rpc_port);
|
||||||
|
wait_for_http_server(args.rpc_port).await?;
|
||||||
|
info!("HTTP server is ready");
|
||||||
|
|
||||||
let existing_node: Box<dyn revive_dt_node_interaction::EthereumNode> = match args.platform {
|
let existing_node: Box<dyn revive_dt_node_interaction::EthereumNode> = match args.platform {
|
||||||
PlatformIdentifier::GethEvmSolc | PlatformIdentifier::LighthouseGethEvmSolc =>
|
PlatformIdentifier::GethEvmSolc | PlatformIdentifier::LighthouseGethEvmSolc =>
|
||||||
Box::new(
|
Box::new(
|
||||||
@@ -208,18 +260,27 @@ async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
|||||||
mf
|
mf
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("test {} ... {RED}FAILED{COLOUR_RESET}", file_display);
|
// Skip files without metadata instead of treating them as failures
|
||||||
println!(" Error loading metadata: {}", e);
|
info!("Skipping {} (no metadata): {}", file_display, e);
|
||||||
failed_files += 1;
|
skipped_files += 1;
|
||||||
failures.push((file_display.clone(), format!("Error loading metadata: {}", e)));
|
|
||||||
if args.bail {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
match execute_test_file(&metadata_file, platform, node, &context).await {
|
// Execute test with 10 second timeout
|
||||||
|
let test_result = tokio::time::timeout(
|
||||||
|
Duration::from_secs(20),
|
||||||
|
execute_test_file(&metadata_file, platform, node, &context),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let result = match test_result {
|
||||||
|
Ok(Ok(_)) => Ok(()),
|
||||||
|
Ok(Err(e)) => Err(e),
|
||||||
|
Err(_) => Err(anyhow::anyhow!("Test timed out after 20 seconds")),
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
println!("test {file_display} ... {GREEN}ok{COLOUR_RESET}");
|
println!("test {file_display} ... {GREEN}ok{COLOUR_RESET}");
|
||||||
passed_files += 1;
|
passed_files += 1;
|
||||||
@@ -237,7 +298,16 @@ async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
|||||||
println!("test {file_display} ... {RED}FAILED{COLOUR_RESET}");
|
println!("test {file_display} ... {RED}FAILED{COLOUR_RESET}");
|
||||||
failed_files += 1;
|
failed_files += 1;
|
||||||
let error_detail = if args.verbose { format!("{:?}", e) } else { format!("{}", e) };
|
let error_detail = if args.verbose { format!("{:?}", e) } else { format!("{}", e) };
|
||||||
failures.push((file_display, error_detail));
|
failures.push((file_display.clone(), error_detail));
|
||||||
|
|
||||||
|
// Update cached-failed
|
||||||
|
{
|
||||||
|
let mut cache = cached_failed.lock().await;
|
||||||
|
cache.insert(file_display);
|
||||||
|
if let Err(e) = save_cached_failed(&cached_failed_path, &cache) {
|
||||||
|
info!("Failed to save cached-failed: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if args.bail {
|
if args.bail {
|
||||||
info!("Bailing after first failure");
|
info!("Bailing after first failure");
|
||||||
@@ -551,3 +621,19 @@ fn save_cached_passed(path: &Path, cache: &HashSet<String>) -> anyhow::Result<()
|
|||||||
writer.flush()?;
|
writer.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save cached failed tests to file
|
||||||
|
fn save_cached_failed(path: &Path, cache: &HashSet<String>) -> anyhow::Result<()> {
|
||||||
|
let file = File::create(path).context("Failed to create cached-failed file")?;
|
||||||
|
let mut writer = BufWriter::new(file);
|
||||||
|
|
||||||
|
let mut entries: Vec<_> = cache.iter().collect();
|
||||||
|
entries.sort();
|
||||||
|
|
||||||
|
for entry in entries {
|
||||||
|
writeln!(writer, "{}", entry)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.flush()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,12 +51,9 @@ where
|
|||||||
provider: &P,
|
provider: &P,
|
||||||
tx: &<N as Network>::TransactionRequest,
|
tx: &<N as Network>::TransactionRequest,
|
||||||
) -> TransportResult<Self::Fillable> {
|
) -> TransportResult<Self::Fillable> {
|
||||||
// Try to fetch GasFiller’s “fillable” (gas_price, base_fee, estimate_gas, …)
|
// Try to fetch GasFiller's "fillable" (gas_price, base_fee, estimate_gas, …)
|
||||||
// If it errors (i.e. tx would revert under eth_estimateGas), swallow it.
|
// Propagate errors so caller can handle them appropriately
|
||||||
match self.inner.prepare(provider, tx).await {
|
self.inner.prepare(provider, tx).await.map(Some)
|
||||||
Ok(fill) => Ok(Some(fill)),
|
|
||||||
Err(_) => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fill(
|
async fn fill(
|
||||||
|
|||||||
Reference in New Issue
Block a user