Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment on lines +44 to +45
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cargo test invocation will also run doctests; the repo currently has at least one runnable doctest in src/commands/status/mod.rs (module-level "Usage" example) that calls status::status() and will fail on a clean CI environment (requires an initialized config). Either mark that doctest as no_run/ignore (preferred) or adjust CI to avoid running doctests until the docs are fixed, otherwise this job is likely to be flaky/fail consistently.

Copilot uses AI. Check for mistakes.

foc-start-test:
runs-on: ["self-hosted", "linux", "x64", "16xlarge+gpu"]
timeout-minutes: 60
Expand Down
2 changes: 1 addition & 1 deletion src/commands/init/keys.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
30 changes: 1 addition & 29 deletions src/commands/start/step/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<dyn Error>> {
/// 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<dyn Error>> {
/// 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)
Expand Down Expand Up @@ -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");
Expand Down
18 changes: 0 additions & 18 deletions src/commands/status/git/formatters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
17 changes: 0 additions & 17 deletions src/commands/status/git/git_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 3 additions & 3 deletions src/commands/status/git/repo_paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
/// ```
///
Expand Down
15 changes: 3 additions & 12 deletions src/commands/status/running.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
);
Comment on lines 180 to 192
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extract_base_image_name currently splits on - and assumes the run ID contains no -. However save_current_run_id/tests in run_id::persistence accept hyphenated run IDs (e.g. "251203-1246-test-wolf"), which would make container names like foc-<run_id>-lotus parse incorrectly and return the wrong base image name. Consider making extract_base_image_name robust to - in the run ID (e.g., parse from the end or match known service suffixes), and add a test case that covers a hyphenated run ID to prevent regressions.

Copilot uses AI. Check for mistakes.
assert_eq!(
Expand Down
30 changes: 0 additions & 30 deletions src/commands/status/uptime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<u64> {
let output = Command::new("docker")
.args([
Expand Down Expand Up @@ -55,16 +45,6 @@ fn get_lotus_block_height() -> Option<u64> {
/// 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<f32> {
let output = Command::new("docker")
.args([
Expand Down Expand Up @@ -101,16 +81,6 @@ fn get_containers_cpu_usage() -> Option<f32> {
/// 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([
Expand Down
12 changes: 6 additions & 6 deletions src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ pub const REQUIRED_DOCKER_IMAGES: &[&str] = &[
];

/// Docker container names (base - will be prefixed with foc-c-<RUN_ID>- 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";
Comment on lines 34 to +40
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above these container name constants still says they’ll be prefixed with foc-c-<RUN_ID>-, but the codebase now uses foc-<RUN_ID>-<service> (and these constants are also used directly when no run ID is present). Please update this doc comment to reflect the actual naming scheme to avoid misleading future changes.

Copilot uses AI. Check for mistakes.

/// Port numbers
pub const LOTUS_RPC_PORT: u16 = 1234;
Expand Down
6 changes: 0 additions & 6 deletions src/docker/command_logger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
8 changes: 0 additions & 8 deletions src/embedded_assets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<dyn Error>> {
// Create target directory if it doesn't exist
fs::create_dir_all(target_dir)?;
Expand Down
14 changes: 12 additions & 2 deletions src/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -297,13 +302,15 @@ 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"));
}

#[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();

Expand All @@ -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();

Expand All @@ -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();

Expand All @@ -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();

Expand All @@ -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
Expand Down
8 changes: 0 additions & 8 deletions src/port_allocator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 0 additions & 6 deletions src/run_id/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
11 changes: 0 additions & 11 deletions src/run_id/persistence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<dyn Error>> {
let state_dir = crate::paths::foc_devnet_state();
fs::create_dir_all(&state_dir)?;
Expand All @@ -54,12 +49,6 @@ pub fn save_current_run_id(run_id: &str) -> Result<(), Box<dyn Error>> {
///
/// # 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<String, Box<dyn Error>> {
let file_path = current_run_id_file();

Expand Down
Loading
Loading