Clean up unused BMAD workflow, agent, and command files across all IDE configurations (.agent, .clinerules, .cursor, .gemini, .github, .kilocode, .opencode) and internal module files (_bmad/bmb, _bmad/bmm). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
296 lines
8.7 KiB
Rust
296 lines
8.7 KiB
Rust
//! Tests for batch execution.
|
|
|
|
use entropyk_cli::batch::{discover_config_files, BatchAggregator, BatchSummary, OutputFormat};
|
|
use entropyk_cli::run::{SimulationResult, SimulationStatus};
|
|
use std::path::PathBuf;
|
|
use std::str::FromStr;
|
|
use tempfile::tempdir;
|
|
|
|
#[test]
|
|
fn test_discover_config_files() {
|
|
let dir = tempdir().unwrap();
|
|
|
|
std::fs::write(dir.path().join("config1.json"), "{}").unwrap();
|
|
std::fs::write(dir.path().join("config2.json"), "{}").unwrap();
|
|
std::fs::write(dir.path().join("config3.json"), "{}").unwrap();
|
|
std::fs::write(dir.path().join("readme.txt"), "").unwrap();
|
|
std::fs::write(dir.path().join("data.csv"), "a,b,c").unwrap();
|
|
|
|
let files = discover_config_files(dir.path()).unwrap();
|
|
assert_eq!(files.len(), 3);
|
|
|
|
let names: Vec<String> = files
|
|
.iter()
|
|
.map(|p: &PathBuf| p.file_name().unwrap().to_string_lossy().to_string())
|
|
.collect();
|
|
assert!(names.contains(&"config1.json".to_string()));
|
|
assert!(names.contains(&"config2.json".to_string()));
|
|
assert!(names.contains(&"config3.json".to_string()));
|
|
}
|
|
|
|
#[test]
|
|
fn test_discover_config_files_sorted() {
|
|
let dir = tempdir().unwrap();
|
|
|
|
std::fs::write(dir.path().join("zebra.json"), "{}").unwrap();
|
|
std::fs::write(dir.path().join("alpha.json"), "{}").unwrap();
|
|
std::fs::write(dir.path().join("middle.json"), "{}").unwrap();
|
|
|
|
let files = discover_config_files(dir.path()).unwrap();
|
|
assert_eq!(files.len(), 3);
|
|
assert!(files[0].ends_with("alpha.json"));
|
|
assert!(files[1].ends_with("middle.json"));
|
|
assert!(files[2].ends_with("zebra.json"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_discover_empty_directory() {
|
|
let dir = tempdir().unwrap();
|
|
let files = discover_config_files(dir.path()).unwrap();
|
|
assert!(files.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn test_batch_summary_serialization() {
|
|
let summary = BatchSummary {
|
|
total: 100,
|
|
succeeded: 95,
|
|
failed: 3,
|
|
non_converged: 2,
|
|
total_elapsed_ms: 5000,
|
|
avg_elapsed_ms: 50.0,
|
|
results: vec![],
|
|
};
|
|
|
|
let json = serde_json::to_string_pretty(&summary).unwrap();
|
|
assert!(json.contains("\"total\": 100"));
|
|
assert!(json.contains("\"succeeded\": 95"));
|
|
assert!(json.contains("\"avg_elapsed_ms\": 50.0"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_batch_summary_default() {
|
|
let summary = BatchSummary::default();
|
|
assert_eq!(summary.total, 0);
|
|
assert_eq!(summary.succeeded, 0);
|
|
assert_eq!(summary.failed, 0);
|
|
assert!(summary.results.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn test_simulation_result_statuses() {
|
|
let results = vec![
|
|
SimulationResult {
|
|
input: "ok.json".to_string(),
|
|
status: SimulationStatus::Converged,
|
|
convergence: None,
|
|
iterations: Some(10),
|
|
state: None,
|
|
performance: None,
|
|
error: None,
|
|
elapsed_ms: 50,
|
|
},
|
|
SimulationResult {
|
|
input: "fail.json".to_string(),
|
|
status: SimulationStatus::Error,
|
|
convergence: None,
|
|
iterations: None,
|
|
state: None,
|
|
performance: None,
|
|
error: Some("Error".to_string()),
|
|
elapsed_ms: 0,
|
|
},
|
|
SimulationResult {
|
|
input: "timeout.json".to_string(),
|
|
status: SimulationStatus::Timeout,
|
|
convergence: None,
|
|
iterations: Some(100),
|
|
state: None,
|
|
performance: None,
|
|
error: None,
|
|
elapsed_ms: 1000,
|
|
},
|
|
];
|
|
|
|
let converged_count = results
|
|
.iter()
|
|
.filter(|r| r.status == SimulationStatus::Converged)
|
|
.count();
|
|
let error_count = results
|
|
.iter()
|
|
.filter(|r| r.status == SimulationStatus::Error)
|
|
.count();
|
|
let timeout_count = results
|
|
.iter()
|
|
.filter(|r| r.status == SimulationStatus::Timeout)
|
|
.count();
|
|
|
|
assert_eq!(converged_count, 1);
|
|
assert_eq!(error_count, 1);
|
|
assert_eq!(timeout_count, 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_batch_aggregator_csv_output() {
|
|
let results = vec![
|
|
SimulationResult {
|
|
input: "scenario1.json".to_string(),
|
|
status: SimulationStatus::Converged,
|
|
convergence: Some(entropyk_cli::run::ConvergenceInfo {
|
|
final_residual: 1e-8,
|
|
tolerance: 1e-6,
|
|
}),
|
|
iterations: Some(25),
|
|
state: None,
|
|
performance: None,
|
|
error: None,
|
|
elapsed_ms: 150,
|
|
},
|
|
SimulationResult {
|
|
input: "scenario2.json".to_string(),
|
|
status: SimulationStatus::Converged,
|
|
convergence: Some(entropyk_cli::run::ConvergenceInfo {
|
|
final_residual: 5e-7,
|
|
tolerance: 1e-6,
|
|
}),
|
|
iterations: Some(30),
|
|
state: None,
|
|
performance: None,
|
|
error: None,
|
|
elapsed_ms: 200,
|
|
},
|
|
SimulationResult {
|
|
input: "scenario3.json".to_string(),
|
|
status: SimulationStatus::Error,
|
|
convergence: None,
|
|
iterations: None,
|
|
state: None,
|
|
performance: None,
|
|
error: Some("Solver failed".to_string()),
|
|
elapsed_ms: 0,
|
|
},
|
|
];
|
|
|
|
let aggregator = BatchAggregator::new(results);
|
|
let csv = aggregator.to_csv();
|
|
let lines: Vec<&str> = csv.lines().collect();
|
|
|
|
// Header + 3 data lines
|
|
assert_eq!(lines.len(), 4);
|
|
assert!(lines[0].contains("input,status,iterations,converged"));
|
|
assert!(lines[1].contains("scenario1.json"));
|
|
assert!(lines[1].contains("converged"));
|
|
assert!(lines[1].contains("true"));
|
|
assert!(lines[3].contains("error"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_batch_aggregator_json_summary() {
|
|
let results = vec![
|
|
SimulationResult {
|
|
input: "test1.json".to_string(),
|
|
status: SimulationStatus::Converged,
|
|
convergence: None,
|
|
iterations: Some(10),
|
|
state: None,
|
|
performance: None,
|
|
error: None,
|
|
elapsed_ms: 50,
|
|
},
|
|
SimulationResult {
|
|
input: "test2.json".to_string(),
|
|
status: SimulationStatus::Converged,
|
|
convergence: None,
|
|
iterations: Some(15),
|
|
state: None,
|
|
performance: None,
|
|
error: None,
|
|
elapsed_ms: 75,
|
|
},
|
|
SimulationResult {
|
|
input: "test3.json".to_string(),
|
|
status: SimulationStatus::Timeout,
|
|
convergence: None,
|
|
iterations: Some(100),
|
|
state: None,
|
|
performance: None,
|
|
error: None,
|
|
elapsed_ms: 5000,
|
|
},
|
|
];
|
|
|
|
let aggregator = BatchAggregator::new(results);
|
|
let summary = aggregator.summary();
|
|
|
|
assert_eq!(summary.total, 3);
|
|
assert_eq!(summary.succeeded, 2);
|
|
assert_eq!(summary.failed, 0);
|
|
assert_eq!(summary.non_converged, 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_output_format_parsing() {
|
|
assert_eq!(OutputFormat::from_str("json").unwrap(), OutputFormat::Json);
|
|
assert_eq!(OutputFormat::from_str("JSON").unwrap(), OutputFormat::Json);
|
|
assert_eq!(OutputFormat::from_str("csv").unwrap(), OutputFormat::Csv);
|
|
assert_eq!(OutputFormat::from_str("CSV").unwrap(), OutputFormat::Csv);
|
|
assert!(OutputFormat::from_str("xml").is_err());
|
|
assert!(OutputFormat::from_str("invalid").is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_batch_summary_json_serialization_roundtrip() {
|
|
let summary = BatchSummary {
|
|
total: 20,
|
|
succeeded: 18,
|
|
failed: 1,
|
|
non_converged: 1,
|
|
total_elapsed_ms: 5000,
|
|
avg_elapsed_ms: 250.0,
|
|
results: vec![],
|
|
};
|
|
|
|
let json = summary.to_json().unwrap();
|
|
let deserialized: BatchSummary = serde_json::from_str(&json).unwrap();
|
|
|
|
assert_eq!(deserialized.total, 20);
|
|
assert_eq!(deserialized.succeeded, 18);
|
|
assert_eq!(deserialized.failed, 1);
|
|
assert_eq!(deserialized.non_converged, 1);
|
|
assert_eq!(deserialized.total_elapsed_ms, 5000);
|
|
}
|
|
|
|
#[test]
|
|
fn test_batch_summary_csv_with_convergence() {
|
|
let results = vec![SimulationResult {
|
|
input: "config1.json".to_string(),
|
|
status: SimulationStatus::Converged,
|
|
convergence: Some(entropyk_cli::run::ConvergenceInfo {
|
|
final_residual: 1e-9,
|
|
tolerance: 1e-6,
|
|
}),
|
|
iterations: Some(42),
|
|
state: None,
|
|
performance: None,
|
|
error: None,
|
|
elapsed_ms: 300,
|
|
}];
|
|
|
|
let summary = BatchSummary {
|
|
total: 1,
|
|
succeeded: 1,
|
|
failed: 0,
|
|
non_converged: 0,
|
|
total_elapsed_ms: 300,
|
|
avg_elapsed_ms: 300.0,
|
|
results,
|
|
};
|
|
|
|
let csv = summary.to_csv();
|
|
assert!(csv.contains("config1.json"));
|
|
assert!(csv.contains("converged"));
|
|
assert!(csv.contains("42"));
|
|
assert!(csv.contains("1.00e-9"));
|
|
assert!(csv.contains("300"));
|
|
}
|