From 5e9def2a9af268b3cbcc55b138dac436a67d2e91 Mon Sep 17 00:00:00 2001 From: Simon Paitrault Date: Wed, 20 Dec 2023 17:47:35 +0100 Subject: [PATCH] chore: adding test for sigterm Signed-off-by: Simon Paitrault --- Cargo.lock | 25 +++++++++++ crates/topos/Cargo.toml | 1 + crates/topos/tests/config.rs | 58 +++--------------------- crates/topos/tests/node.rs | 86 +++++++++++++++++++++++++++++++++++- crates/topos/tests/utils.rs | 59 +++++++++++++++++++++++++ 5 files changed, 175 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8035c453..b7575b5c3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4576,6 +4576,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -6847,6 +6856,21 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "sysinfo" +version = "0.29.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd727fc423c2060f6c92d9534cef765c65a6ed3f428a03d7def74a8c4348e666" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "winapi", +] + [[package]] name = "system-configuration" version = "0.5.1" @@ -7366,6 +7390,7 @@ dependencies = [ "rstest", "serde", "serde_json", + "sysinfo", "tar", "tempfile", "test-log", diff --git a/crates/topos/Cargo.toml b/crates/topos/Cargo.toml index 2ce533d53..b349761d5 100644 --- a/crates/topos/Cargo.toml +++ b/crates/topos/Cargo.toml @@ -68,6 +68,7 @@ insta = { version = "1.21", features = ["json", "redactions"] } rstest = { workspace = true, features = ["async-timeout"] } tempfile = "3.8.0" predicates = "3.0.3" +sysinfo = "0.29.11" [features] default = [] diff --git a/crates/topos/tests/config.rs b/crates/topos/tests/config.rs index 0e29e840c..f4e349675 100644 --- a/crates/topos/tests/config.rs +++ b/crates/topos/tests/config.rs @@ -5,58 +5,9 @@ use std::process::Command; use tempfile::tempdir; use topos::install_polygon_edge; -async fn setup_polygon_edge(path: &str) -> String { - let installation_path = std::env::current_dir().unwrap().join(path); - let binary_path = installation_path.join("polygon-edge"); - - if !binary_path.exists() { - std::fs::create_dir_all(installation_path.clone()) - .expect("Cannot create test binary folder"); - - install_polygon_edge( - "topos-protocol/polygon-edge".to_string(), - None, - installation_path.clone().as_path(), - ) - .await - .expect("Cannot install Polygon Edge binary"); - } - - installation_path.to_str().unwrap().to_string() -} +use crate::utils::setup_polygon_edge; -async fn generate_polygon_edge_genesis_file( - polygon_edge_bin: &str, - home_path: &str, - node_name: &str, - subnet: &str, -) -> Result<(), Box> { - let genesis_folder_path: PathBuf = PathBuf::from(format!("{}/subnet/{}", home_path, subnet)); - if !genesis_folder_path.exists() { - std::fs::create_dir_all(genesis_folder_path.clone()) - .expect("Cannot create subnet genesis file folder"); - } - let genesis_file_path = format!("{}/genesis.json", genesis_folder_path.display()); - println!("Polygon edge path: {}", polygon_edge_bin); - let mut cmd = Command::new(polygon_edge_bin); - let val_prefix_path = format!("{}/node/{}/", home_path, node_name); - cmd.arg("genesis") - .arg("--dir") - .arg(&genesis_file_path) - .arg("--consensus") - .arg("ibft") - .arg("--ibft-validators-prefix-path") - .arg(val_prefix_path) - .arg("--bootnode") /* set dummy bootnode, we will not run edge to produce blocks */ - .arg("/ip4/127.0.0.1/tcp/8545/p2p/16Uiu2HAmNYneHCbJ1Ntz1ojvTdiNGCMGWNT5MGMH28AzKNV66Paa"); - cmd.assert() - .success() - .stdout(predicate::str::contains(format!( - "Genesis written to {}", - genesis_folder_path.display() - ))); - Ok(()) -} +mod utils; #[tokio::test] async fn handle_command_init() -> Result<(), Box> { @@ -320,7 +271,7 @@ async fn command_node_up() -> Result<(), Box> { // Generate polygon edge genesis file let polygon_edge_bin = format!("{}/polygon-edge", node_edge_path_env); - generate_polygon_edge_genesis_file( + utils::generate_polygon_edge_genesis_file( &polygon_edge_bin, node_up_home_env, node_up_name_env, @@ -340,13 +291,14 @@ async fn command_node_up() -> Result<(), Box> { .env("TOPOS_NODE_NAME", node_up_name_env) .arg("up"); let mut cmd = tokio::process::Command::from(cmd).spawn().unwrap(); - let output = tokio::time::timeout(std::time::Duration::from_secs(60), cmd.wait()).await; + let output = tokio::time::timeout(std::time::Duration::from_secs(10), cmd.wait()).await; // Check if node up was successful match output { Ok(Ok(exit_status)) => { if !exit_status.success() { println!("Exited with error output {:?}", exit_status.code()); + cmd.kill().await?; panic!("Node up failed"); } } diff --git a/crates/topos/tests/node.rs b/crates/topos/tests/node.rs index 1b4aecdf3..afa76c4ae 100644 --- a/crates/topos/tests/node.rs +++ b/crates/topos/tests/node.rs @@ -1,8 +1,16 @@ mod utils; -use std::process::Command; +use std::{ + path::PathBuf, + process::{Command, ExitStatus}, + thread, +}; use assert_cmd::prelude::*; +use sysinfo::{Pid, PidExt, ProcessExt, Signal, System, SystemExt}; +use tempfile::tempdir; + +use crate::utils::generate_polygon_edge_genesis_file; #[test] fn help_display() -> Result<(), Box> { @@ -17,3 +25,79 @@ fn help_display() -> Result<(), Box> { Ok(()) } + +/// Test node up running from config file +#[test_log::test(tokio::test)] +async fn command_node_up_sigterm() -> Result<(), Box> { + let tmp_home_dir = tempdir()?; + + // Create config file + let node_up_home_env = tmp_home_dir.path().to_str().unwrap(); + let node_edge_path_env = utils::setup_polygon_edge(node_up_home_env).await; + let node_up_name_env = "TEST_NODE_UP"; + let node_up_role_env = "full-node"; + let node_up_subnet_env = "topos-up-env-subnet"; + + let mut cmd = Command::cargo_bin("topos")?; + cmd.arg("node") + .env("TOPOS_POLYGON_EDGE_BIN_PATH", &node_edge_path_env) + .env("TOPOS_HOME", node_up_home_env) + .env("TOPOS_NODE_NAME", node_up_name_env) + .env("TOPOS_NODE_ROLE", node_up_role_env) + .env("TOPOS_NODE_SUBNET", node_up_subnet_env) + .arg("init"); + + let output = cmd.assert().success(); + let result: &str = std::str::from_utf8(&output.get_output().stdout)?; + assert!(result.contains("Created node config file")); + + // Run node init with cli flags + let home = PathBuf::from(node_up_home_env); + // Verification: check that the config file was created + let config_path = home.join("node").join(node_up_name_env).join("config.toml"); + assert!(config_path.exists()); + + // Generate polygon edge genesis file + let polygon_edge_bin = format!("{}/polygon-edge", node_edge_path_env); + generate_polygon_edge_genesis_file( + &polygon_edge_bin, + node_up_home_env, + node_up_name_env, + node_up_subnet_env, + ) + .await?; + let polygon_edge_genesis_path = home + .join("subnet") + .join(node_up_subnet_env) + .join("genesis.json"); + assert!(polygon_edge_genesis_path.exists()); + + let mut cmd = Command::cargo_bin("topos")?; + cmd.arg("node") + .env("TOPOS_POLYGON_EDGE_BIN_PATH", &node_edge_path_env) + .env("TOPOS_HOME", node_up_home_env) + .env("TOPOS_NODE_NAME", node_up_name_env) + .arg("up"); + + let mut cmd = tokio::process::Command::from(cmd).spawn().unwrap(); + let pid = cmd.id().unwrap(); + let sigterm_wait = tokio::time::sleep(std::time::Duration::from_secs(10)).await; + + let s = System::new_all(); + if let Some(process) = s.process(Pid::from_u32(pid)) { + if process.kill_with(Signal::Term).is_none() { + eprintln!("This signal isn't supported on this platform"); + } + } + + if let Ok(code) = cmd.wait().await { + assert!(code.success()); + } else { + panic!("Failed to gracefull shutdown"); + } + + // Cleanup + std::fs::remove_dir_all(node_up_home_env)?; + + Ok(()) +} diff --git a/crates/topos/tests/utils.rs b/crates/topos/tests/utils.rs index 01002ac6b..a96fe102d 100644 --- a/crates/topos/tests/utils.rs +++ b/crates/topos/tests/utils.rs @@ -1,4 +1,10 @@ +use assert_cmd::prelude::*; +use predicates::prelude::*; use regex::Regex; +use std::path::PathBuf; +use std::process::Command; +use tempfile::tempdir; +use topos::install_polygon_edge; #[cfg(test)] pub fn sanitize_config_folder_path(cmd_out: &str) -> String { @@ -10,3 +16,56 @@ pub fn sanitize_config_folder_path(cmd_out: &str) -> String { .replace(cmd_out, "[default: /home/runner/.config/topos]") .to_string() } + +pub async fn setup_polygon_edge(path: &str) -> String { + let installation_path = std::env::current_dir().unwrap().join(path); + let binary_path = installation_path.join("polygon-edge"); + + if !binary_path.exists() { + std::fs::create_dir_all(installation_path.clone()) + .expect("Cannot create test binary folder"); + + install_polygon_edge( + "topos-protocol/polygon-edge".to_string(), + None, + installation_path.clone().as_path(), + ) + .await + .expect("Cannot install Polygon Edge binary"); + } + + installation_path.to_str().unwrap().to_string() +} + +pub async fn generate_polygon_edge_genesis_file( + polygon_edge_bin: &str, + home_path: &str, + node_name: &str, + subnet: &str, +) -> Result<(), Box> { + let genesis_folder_path: PathBuf = PathBuf::from(format!("{}/subnet/{}", home_path, subnet)); + if !genesis_folder_path.exists() { + std::fs::create_dir_all(genesis_folder_path.clone()) + .expect("Cannot create subnet genesis file folder"); + } + let genesis_file_path = format!("{}/genesis.json", genesis_folder_path.display()); + println!("Polygon edge path: {}", polygon_edge_bin); + let mut cmd = Command::new(polygon_edge_bin); + let val_prefix_path = format!("{}/node/{}/", home_path, node_name); + cmd.arg("genesis") + .arg("--dir") + .arg(&genesis_file_path) + .arg("--consensus") + .arg("ibft") + .arg("--ibft-validators-prefix-path") + .arg(val_prefix_path) + .arg("--bootnode") /* set dummy bootnode, we will not run edge to produce blocks */ + .arg("/ip4/127.0.0.1/tcp/8545/p2p/16Uiu2HAmNYneHCbJ1Ntz1ojvTdiNGCMGWNT5MGMH28AzKNV66Paa"); + cmd.assert() + .success() + .stdout(predicate::str::contains(format!( + "Genesis written to {}", + genesis_folder_path.display() + ))); + Ok(()) +}