mecha10-cli 0.8.0

Mecha10 CLI tool
Documentation
//! Tests for the per-environment `environments.<env>.logging.disk_logging_enabled`
//! project config toggle (LAB-2041)

use mecha10_cli::services::process::ProcessService;
use serial_test::serial;
use std::collections::HashMap;
use std::fs;
use std::path::Path;
use tempfile::TempDir;

/// Write a minimal mecha10.json whose `dev` environment optionally has an explicit
/// `logging.disk_logging_enabled` value. `None` omits the `logging` section entirely, to
/// exercise the default.
fn write_project_config(dir: &Path, disk_logging_enabled: Option<bool>) {
    let logging_section = match disk_logging_enabled {
        Some(enabled) => format!(r#", "logging": {{ "disk_logging_enabled": {} }}"#, enabled),
        None => String::new(),
    };

    let json = format!(
        r#"{{
            "name": "test-project",
            "version": "0.1.0",
            "robot_id": "test-robot",
            "environments": {{
                "dev": {{ "control_plane": "https://dev.example.com"{} }}
            }}
        }}"#,
        logging_section
    );

    fs::write(dir.join("mecha10.json"), json).expect("write mecha10.json");
}

/// Spawn a short-lived process via `spawn_with_env` from within `dir` and wait
/// for it to actually run (so any log file it would create has been opened).
fn spawn_and_settle(service: &mut ProcessService, name: &str) {
    let mut env = HashMap::new();
    env.insert("TEST_VAR".to_string(), "1".to_string());

    service
        .spawn_with_env(name, "sleep", &["1"], env)
        .expect("spawn_with_env should succeed");

    std::thread::sleep(std::time::Duration::from_millis(150));
}

#[test]
#[serial]
fn disk_logging_enabled_by_default_when_no_logging_section() {
    let temp = TempDir::new().unwrap();
    write_project_config(temp.path(), None);

    let original_dir = std::env::current_dir().unwrap();
    std::env::set_current_dir(temp.path()).unwrap();

    let mut service = ProcessService::new();
    spawn_and_settle(&mut service, "default-node");

    let log_path = temp.path().join("logs").join("default-node.log");
    assert!(
        log_path.exists(),
        "expected disk log file to be created by default (existing behavior unchanged)"
    );

    service.cleanup();
    std::env::set_current_dir(original_dir).unwrap();
}

#[test]
#[serial]
fn disk_logging_explicitly_enabled_writes_log_file() {
    let temp = TempDir::new().unwrap();
    write_project_config(temp.path(), Some(true));

    let original_dir = std::env::current_dir().unwrap();
    std::env::set_current_dir(temp.path()).unwrap();

    let mut service = ProcessService::new();
    spawn_and_settle(&mut service, "enabled-node");

    let log_path = temp.path().join("logs").join("enabled-node.log");
    assert!(log_path.exists(), "expected disk log file when explicitly enabled");

    service.cleanup();
    std::env::set_current_dir(original_dir).unwrap();
}

/// LAB-2041's core requirement: the override is resolved off the *current* environment,
/// not applied globally. `MECHA10_ENV=production` selects `prod`, which has no override
/// of its own (so it keeps the default of enabled).
#[test]
#[serial]
fn disk_logging_resolves_off_current_environment_not_other_environments() {
    let temp = TempDir::new().unwrap();
    let json = r#"{
        "name": "test-project",
        "version": "0.1.0",
        "robot_id": "test-robot",
        "environments": {
            "dev": { "control_plane": "https://dev.example.com", "logging": { "disk_logging_enabled": false } },
            "prod": { "control_plane": "https://prod.example.com" }
        }
    }"#;
    fs::write(temp.path().join("mecha10.json"), json).expect("write mecha10.json");

    let original_dir = std::env::current_dir().unwrap();
    std::env::set_current_dir(temp.path()).unwrap();
    std::env::set_var("MECHA10_ENV", "production");

    let mut service = ProcessService::new();
    spawn_and_settle(&mut service, "prod-node");

    let log_path = temp.path().join("logs").join("prod-node.log");
    assert!(
        log_path.exists(),
        "prod has no logging override, so it should log to disk regardless of dev's override"
    );

    service.cleanup();
    std::env::remove_var("MECHA10_ENV");
    std::env::set_current_dir(original_dir).unwrap();
}

#[test]
#[serial]
fn disk_logging_disabled_creates_no_log_file_or_directory() {
    let temp = TempDir::new().unwrap();
    write_project_config(temp.path(), Some(false));

    let original_dir = std::env::current_dir().unwrap();
    std::env::set_current_dir(temp.path()).unwrap();

    let mut service = ProcessService::new();
    spawn_and_settle(&mut service, "quiet-node");

    let logs_dir = temp.path().join("logs");
    assert!(
        !logs_dir.exists(),
        "logs/ directory should never be created when disk logging is disabled"
    );

    service.cleanup();
    std::env::set_current_dir(original_dir).unwrap();
}