diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a82ffc3..f6c50be8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,24 @@ jobs: - name: Run clippy run: cargo clippy --all-targets --all-features -- -D warnings + cargo-test: + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - uses: actions/checkout@v4 + + - name: Setup Rust toolchain + uses: actions-rust-lang/setup-rust-toolchain@v1 + + - name: Install build dependencies + run: | + sudo apt-get update + sudo apt-get install -y pkg-config libssl-dev + + - name: Run tests + run: cargo test --all-targets --all-features + foc-start-test: runs-on: ["self-hosted", "linux", "x64", "16xlarge+gpu"] timeout-minutes: 60 diff --git a/src/commands/init/keys.rs b/src/commands/init/keys.rs index db151b73..e2e2f249 100644 --- a/src/commands/init/keys.rs +++ b/src/commands/init/keys.rs @@ -142,7 +142,7 @@ mod tests { let keys = generate_keys(false).unwrap(); // Check that we have the expected number of keys - assert_eq!(keys.len(), 8); // 3 BLS + 5 Ethereum + assert_eq!(keys.len(), 14); // 3 BLS + 11 Ethereum // Check that BLS keys are present let bls_keys: Vec<_> = keys diff --git a/src/commands/start/step/mod.rs b/src/commands/start/step/mod.rs index 8ab1842f..7646578b 100644 --- a/src/commands/start/step/mod.rs +++ b/src/commands/start/step/mod.rs @@ -25,28 +25,7 @@ use crate::port_allocator::PortAllocator; /// Steps should use the context to communicate important information to downstream steps: /// - **Early steps** write values using `context.set(key, value)` /// - **Later steps** read values using `context.get(key)` -/// -/// # Example -/// -/// ```rust -/// // Step 1: ETHAccFundingStep creates an address and stores it -/// fn execute(&self, context: &SetupContext) -> Result<(), Box> { -/// let deployer_address = create_deployer_address()?; -/// context.set("deployer_mockusdfc_eth_address", &deployer_address); -/// Ok(()) -/// } -/// -/// // Step 2: USDFCDeployStep reads the address and uses it -/// fn execute(&self, context: &SetupContext) -> Result<(), Box> { -/// let deployer_address = context -/// .get("deployer_mockusdfc_eth_address") -/// .ok_or("Deployer address not found")?; -/// -/// let contract_address = deploy_contract(&deployer_address)?; -/// context.set("mockusdfc_contract_address", &contract_address); -/// Ok(()) -/// } -/// ``` + #[derive(Debug, Clone)] pub struct SetupContext { /// Shared state that can be passed between steps (thread-safe) @@ -150,13 +129,6 @@ impl SetupContext { /// # Arguments /// * `key` - The key to store the command under (free-form, e.g., "lotus_start", "deploy_mockusdfc") /// * `command_str` - The formatted command string (e.g., "docker run -it ubuntu") - /// - /// # Example - /// ``` - /// context.save_command("lotus_container_create", "docker run -d [LOTUS_CONTAINER]"); - /// // Stored as: "lotus_container_create" = "docker run -d [LOTUS_CONTAINER]" - /// // Also appended to: "command_history" list - /// ``` pub fn save_command(&self, key: &str, command_str: &str) { { let mut state = self.state.lock().expect("Failed to lock state"); diff --git a/src/commands/status/git/formatters.rs b/src/commands/status/git/formatters.rs index 20a92e58..c917870d 100644 --- a/src/commands/status/git/formatters.rs +++ b/src/commands/status/git/formatters.rs @@ -18,24 +18,6 @@ use crate::config::Location; /// - Version/branch/tag information /// - Commit hash (shortened) /// - Status indicator ("Ready" or "Not Ready") -/// -/// # Examples -/// -/// ```rust,no_run -/// use foc_devnet::commands::status::git::formatters::format_location_info; -/// use foc_devnet::commands::status::git::git_info::GitInfo; -/// use foc_devnet::config::{Location, GitBranch}; -/// use std::path::Path; -/// -/// let location = Location::GitBranch(GitBranch { -/// url: "https://github.com/example/repo".to_string(), -/// branch: "main".to_string(), -/// }); -/// let git_info = GitInfo::Branch("main".to_string(), "abc123def456".to_string()); -/// let repo_path = Path::new("/path/to/repo"); -/// -/// let (source_type, version, commit, status) = format_location_info(&location, &git_info, repo_path); -/// ``` pub fn format_location_info( location: &Location, git_info: &GitInfo, diff --git a/src/commands/status/git/git_info.rs b/src/commands/status/git/git_info.rs index eeb643ec..a7b73148 100644 --- a/src/commands/status/git/git_info.rs +++ b/src/commands/status/git/git_info.rs @@ -24,23 +24,6 @@ pub enum GitInfo { /// /// This function attempts to determine the current git state of a repository /// by checking for tags, branches, and commit hashes in order of preference. -/// -/// # Examples -/// -/// ```rust,no_run -/// use foc_devnet::commands::status::git::git_info::get_git_info; -/// use std::path::Path; -/// -/// let repo_path = Path::new("/path/to/repo"); -/// let info = get_git_info(repo_path).unwrap(); -/// match info { -/// GitInfo::Tag(tag) => println!("On tag: {}", tag), -/// GitInfo::Branch(branch, commit) => println!("On branch {} at {}", branch, commit), -/// GitInfo::Commit(commit) => println!("At commit {}", commit), -/// GitInfo::None => println!("No git info available"), -/// } -/// ``` -/// /// # Errors /// /// Returns an error if git commands fail to execute or if the repository path is invalid. diff --git a/src/commands/status/git/repo_paths.rs b/src/commands/status/git/repo_paths.rs index b6fd59e3..1523d562 100644 --- a/src/commands/status/git/repo_paths.rs +++ b/src/commands/status/git/repo_paths.rs @@ -15,12 +15,12 @@ use crate::paths::foc_devnet_code; /// /// ```rust,no_run /// use foc_devnet::commands::status::git::repo_paths::get_repo_path_from_config; -/// use foc_devnet::config::{Location, GitBranch}; +/// use foc_devnet::config::Location; /// -/// let location = Location::GitBranch(GitBranch { +/// let location = Location::GitBranch { /// url: "https://github.com/example/repo".to_string(), /// branch: "main".to_string(), -/// }); +/// }; /// let path = get_repo_path_from_config(&location, "component"); /// ``` /// diff --git a/src/commands/status/running.rs b/src/commands/status/running.rs index 60a4d5eb..5b5b498d 100644 --- a/src/commands/status/running.rs +++ b/src/commands/status/running.rs @@ -21,15 +21,6 @@ use crate::run_id::load_current_run_id; /// This function displays the status of all expected foc-devnet services, /// including Docker containers, their uptime, and port accessibility. /// If a run ID exists, it shows the actual container names with run ID prefix. -/// -/// # Examples -/// -/// ```rust,no_run -/// use foc_devnet::commands::status::running_status::print_running_status; -/// -/// print_running_status().expect("Failed to print running status"); -/// ``` -/// /// # Errors /// /// Returns an error if Docker commands fail. @@ -188,15 +179,15 @@ mod tests { #[test] fn test_extract_base_image_name() { assert_eq!( - extract_base_image_name("foc-26jan02-1058_TizzyTike-lotus"), + extract_base_image_name("foc-20251215T2206_ZanyPip-lotus"), crate::constants::LOTUS_CONTAINER ); assert_eq!( - extract_base_image_name("foc-26jan02-1058_TizzyTike-lotus-miner"), + extract_base_image_name("foc-20251215T2206_ZanyPip-lotus-miner"), crate::constants::LOTUS_MINER_CONTAINER ); assert_eq!( - extract_base_image_name("foc-26jan02-1058_TizzyTike-curio-1"), + extract_base_image_name("foc-20251215T2206_ZanyPip-curio-1"), crate::constants::CURIO_CONTAINER ); assert_eq!( diff --git a/src/commands/status/uptime.rs b/src/commands/status/uptime.rs index f6761cde..c334ba9a 100644 --- a/src/commands/status/uptime.rs +++ b/src/commands/status/uptime.rs @@ -18,16 +18,6 @@ use crate::docker::status::{get_container_start_time, get_running_foc_containers /// /// This function queries the lotus node to get the current block height of the chain. /// Returns `None` if the lotus container is not running or if the command fails. -/// -/// # Examples -/// -/// ```rust,no_run -/// use foc_devnet::commands::status::uptime::get_lotus_block_height; -/// -/// if let Some(height) = get_lotus_block_height() { -/// println!("Current block height: {}", height); -/// } -/// ``` fn get_lotus_block_height() -> Option { let output = Command::new("docker") .args([ @@ -55,16 +45,6 @@ fn get_lotus_block_height() -> Option { /// Get the current CPU usage for foc- containers as a percentage. /// /// This function uses docker stats to get the CPU usage of all running foc- containers. -/// -/// # Examples -/// -/// ```rust,no_run -/// use foc_devnet::commands::status::uptime::get_containers_cpu_usage; -/// -/// if let Some(cpu) = get_containers_cpu_usage() { -/// println!("Containers CPU usage: {:.1}%", cpu); -/// } -/// ``` fn get_containers_cpu_usage() -> Option { let output = Command::new("docker") .args([ @@ -101,16 +81,6 @@ fn get_containers_cpu_usage() -> Option { /// Get the current memory usage for foc- containers. /// /// This function returns a tuple of (used_memory_gb, total_limit_gb). -/// -/// # Examples -/// -/// ```rust,no_run -/// use foc_devnet::commands::status::uptime::get_containers_memory_usage; -/// -/// if let Some((used, limit)) = get_containers_memory_usage() { -/// println!("Containers memory: {:.1}GB / {:.1}GB", used, limit); -/// } -/// ``` fn get_containers_memory_usage() -> Option<(f64, f64)> { let output = Command::new("docker") .args([ diff --git a/src/constants.rs b/src/constants.rs index 6097f7a6..24cd0735 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -32,12 +32,12 @@ pub const REQUIRED_DOCKER_IMAGES: &[&str] = &[ ]; /// Docker container names (base - will be prefixed with foc-c-- in practice) -pub const LOTUS_CONTAINER: &str = "foc-c-lotus"; -pub const LOTUS_MINER_CONTAINER: &str = "foc-c-lotus-miner"; -pub const BUILDER_CONTAINER: &str = "foc-c-builder"; -pub const YUGABYTE_CONTAINER: &str = "foc-c-yugabyte"; -pub const CURIO_CONTAINER: &str = "foc-c-curio"; -pub const PORTAINER_CONTAINER: &str = "foc-c-portainer"; +pub const LOTUS_CONTAINER: &str = "foc-lotus"; +pub const LOTUS_MINER_CONTAINER: &str = "foc-lotus-miner"; +pub const BUILDER_CONTAINER: &str = "foc-builder"; +pub const YUGABYTE_CONTAINER: &str = "foc-yugabyte"; +pub const CURIO_CONTAINER: &str = "foc-curio"; +pub const PORTAINER_CONTAINER: &str = "foc-portainer"; /// Port numbers pub const LOTUS_RPC_PORT: u16 = 1234; diff --git a/src/docker/command_logger.rs b/src/docker/command_logger.rs index 98046cbe..c71f09fb 100644 --- a/src/docker/command_logger.rs +++ b/src/docker/command_logger.rs @@ -16,12 +16,6 @@ use std::process::{Command, Output}; /// /// # Returns /// A formatted string representation of the command -/// -/// # Example -/// ``` -/// let cmd = format_command("docker", &["run", "-it", "ubuntu"]); -/// // Returns: "docker run -it ubuntu" -/// ``` pub fn format_command(program: &str, args: &[&str]) -> String { let mut cmd = program.to_string(); for arg in args { diff --git a/src/embedded_assets.rs b/src/embedded_assets.rs index 088ad14b..0b4363fb 100644 --- a/src/embedded_assets.rs +++ b/src/embedded_assets.rs @@ -39,14 +39,6 @@ pub static MOCKUSDFC_ARCHIVE: &[u8] = include_bytes!("../artifacts/MockUSDFC.tar /// # Returns /// /// Returns `Ok(())` if extraction succeeds, or an error if extraction fails -/// -/// # Example -/// -/// ```no_run -/// use std::path::PathBuf; -/// let temp_dir = PathBuf::from("/tmp/mockusdfc"); -/// extract_mockusdfc_project(&temp_dir)?; -/// ``` pub fn extract_mockusdfc_project(target_dir: &PathBuf) -> Result<(), Box> { // Create target directory if it doesn't exist fs::create_dir_all(target_dir)?; diff --git a/src/paths.rs b/src/paths.rs index 18d90a13..7f1fc02f 100644 --- a/src/paths.rs +++ b/src/paths.rs @@ -268,6 +268,11 @@ pub const CONTAINER_FILECOIN_PROOF_PARAMS_PATH: &str = "/var/tmp/filecoin-proof- mod tests { use super::*; use std::env; + use std::sync::Mutex; + + /// Serializes all tests that mutate FOC_DEVNET_BASEDIR to prevent + /// race conditions when the test suite uses multiple threads. + static ENV_MUTEX: Mutex<()> = Mutex::new(()); /// Helper to safely set and restore environment variables in tests struct EnvGuard { @@ -297,6 +302,7 @@ mod tests { #[test] fn test_foc_devnet_home_with_custom_basedir() { + let _lock = ENV_MUTEX.lock().unwrap(); let _guard = EnvGuard::new("FOC_DEVNET_BASEDIR", Some("/tmp/my-foc-devnet")); let path = foc_devnet_home(); assert_eq!(path, PathBuf::from("/tmp/my-foc-devnet")); @@ -304,6 +310,7 @@ mod tests { #[test] fn test_foc_devnet_home_with_tilde_expansion() { + let _lock = ENV_MUTEX.lock().unwrap(); let _guard = EnvGuard::new("FOC_DEVNET_BASEDIR", Some("~/my-foc-devnet")); let path = foc_devnet_home(); @@ -315,6 +322,7 @@ mod tests { #[test] fn test_foc_devnet_home_with_empty_basedir() { + let _lock = ENV_MUTEX.lock().unwrap(); let _guard = EnvGuard::new("FOC_DEVNET_BASEDIR", Some("")); let path = foc_devnet_home(); @@ -327,6 +335,7 @@ mod tests { #[test] fn test_foc_devnet_home_with_whitespace_basedir() { + let _lock = ENV_MUTEX.lock().unwrap(); let _guard = EnvGuard::new("FOC_DEVNET_BASEDIR", Some(" ")); let path = foc_devnet_home(); @@ -339,8 +348,8 @@ mod tests { #[test] fn test_foc_devnet_home_no_env_var() { - // Ensure the env var is not set before the test - env::remove_var("FOC_DEVNET_BASEDIR"); + let _lock = ENV_MUTEX.lock().unwrap(); + let _guard = EnvGuard::new("FOC_DEVNET_BASEDIR", None); let path = foc_devnet_home(); @@ -353,6 +362,7 @@ mod tests { #[test] fn test_dependent_paths_use_foc_devnet_home() { + let _lock = ENV_MUTEX.lock().unwrap(); let _guard = EnvGuard::new("FOC_DEVNET_BASEDIR", Some("/tmp/test-foc")); // All dependent paths should use the custom base directory diff --git a/src/port_allocator.rs b/src/port_allocator.rs index 96822fde..baec84d3 100644 --- a/src/port_allocator.rs +++ b/src/port_allocator.rs @@ -12,14 +12,6 @@ use std::net::TcpListener; /// /// The allocator tracks which ports have been assigned and ensures /// that each allocation is unique and within the configured range. -/// -/// # Example -/// -/// ```rust -/// let mut allocator = PortAllocator::new(5700, 300)?; -/// let lotus_api_port = allocator.allocate()?; // Gets 5700 -/// let lotus_p2p_port = allocator.allocate()?; // Gets 5701 -/// ``` #[derive(Debug)] pub struct PortAllocator { /// Starting port of the range diff --git a/src/run_id/mod.rs b/src/run_id/mod.rs index 6a65fa39..7b3fa969 100644 --- a/src/run_id/mod.rs +++ b/src/run_id/mod.rs @@ -35,12 +35,6 @@ pub const NOUNS: &[&str] = &[ /// - ZanyPip is the random name (adjective + noun) /// /// Uses condensed ISO8601 format (no dashes or colons) for Docker network name compatibility. -/// -/// # Example -/// ```no_run -/// let run_id = generate_run_id(); -/// println!("{}", run_id); // e.g., "20251215T2206_ZanyPip" -/// ``` pub fn generate_run_id() -> String { let now = Local::now(); let datetime = now.format("%Y%m%dT%H%M"); diff --git a/src/run_id/persistence.rs b/src/run_id/persistence.rs index 95e71f00..f847fd0a 100644 --- a/src/run_id/persistence.rs +++ b/src/run_id/persistence.rs @@ -29,11 +29,6 @@ fn current_run_id_file() -> PathBuf { /// /// # Returns /// Ok(()) on success, error on failure -/// -/// # Example -/// ```no_run -/// save_current_run_id("251203-1246-thirsty-wolf")?; -/// ``` pub fn save_current_run_id(run_id: &str) -> Result<(), Box> { let state_dir = crate::paths::foc_devnet_state(); fs::create_dir_all(&state_dir)?; @@ -54,12 +49,6 @@ pub fn save_current_run_id(run_id: &str) -> Result<(), Box> { /// /// # Returns /// The run ID on success, error if file doesn't exist or can't be parsed -/// -/// # Example -/// ```no_run -/// let run_id = load_current_run_id()?; -/// println!("Current run: {}", run_id); -/// ``` pub fn load_current_run_id() -> Result> { let file_path = current_run_id_file(); diff --git a/src/version_info.rs b/src/version_info.rs index d127a52e..e6340e49 100644 --- a/src/version_info.rs +++ b/src/version_info.rs @@ -45,13 +45,6 @@ impl VersionInfo { /// # Arguments /// * `dir` - Directory where version.txt will be created /// * `version_info` - Version information to write -/// -/// # Example -/// ```no_run -/// use std::path::PathBuf; -/// let version_info = VersionInfo::from_env(); -/// write_version_file(&PathBuf::from("/tmp/logs"), &version_info).unwrap(); -/// ``` pub fn write_version_file(dir: &Path, version_info: &VersionInfo) -> Result<(), Box> { let version_file = dir.join("version.txt");