use crate::cook::command::CookCommand;
use crate::cook::orchestrator::CookConfig;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum ExecutionMode {
#[default]
Standard,
MapReduce,
Iterative,
DryRun,
}
impl std::fmt::Display for ExecutionMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ExecutionMode::Standard => write!(f, "Standard"),
ExecutionMode::MapReduce => write!(f, "MapReduce"),
ExecutionMode::Iterative => write!(f, "Iterative"),
ExecutionMode::DryRun => write!(f, "DryRun"),
}
}
}
pub fn detect_execution_mode(config: &CookConfig) -> ExecutionMode {
if config.command.dry_run {
ExecutionMode::DryRun
} else if config.mapreduce_config.is_some() {
ExecutionMode::MapReduce
} else if has_iteration_arguments(&config.command) {
ExecutionMode::Iterative
} else {
ExecutionMode::Standard
}
}
fn has_iteration_arguments(command: &CookCommand) -> bool {
!command.args.is_empty() || !command.map.is_empty()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::mapreduce::{AgentTemplate, MapPhaseYaml, MapReduceWorkflowConfig};
use crate::config::WorkflowConfig;
use std::path::PathBuf;
use std::sync::Arc;
fn create_default_workflow_config() -> WorkflowConfig {
WorkflowConfig {
name: None,
commands: vec![],
env: None,
secrets: None,
env_files: None,
profiles: None,
merge: None,
}
}
fn create_default_mapreduce_config() -> MapReduceWorkflowConfig {
MapReduceWorkflowConfig {
name: "test".to_string(),
mode: "mapreduce".to_string(),
env: None,
secrets: None,
env_files: None,
profiles: None,
setup: None,
map: MapPhaseYaml {
input: "items.json".to_string(),
json_path: "$.items[*]".to_string(),
agent_template: AgentTemplate { commands: vec![] },
max_parallel: "10".to_string(),
filter: None,
sort_by: None,
max_items: None,
offset: None,
distinct: None,
agent_timeout_secs: None,
timeout_config: None,
},
reduce: None,
error_policy: Default::default(),
on_item_failure: None,
continue_on_failure: None,
max_failures: None,
failure_threshold: None,
error_collection: None,
merge: None,
}
}
fn create_default_config() -> CookConfig {
CookConfig {
command: CookCommand {
playbook: PathBuf::from("workflow.yml"),
path: None,
max_iterations: 1,
map: vec![],
args: vec![],
fail_fast: false,
auto_accept: false,
resume: None,
verbosity: 0,
quiet: false,
dry_run: false,
params: Default::default(),
},
project_path: Arc::new(PathBuf::from(".")),
workflow: Arc::new(create_default_workflow_config()),
mapreduce_config: None,
}
}
#[test]
fn test_detect_dry_run_mode() {
let mut config = create_default_config();
config.command.dry_run = true;
assert_eq!(detect_execution_mode(&config), ExecutionMode::DryRun);
}
#[test]
fn test_detect_dry_run_takes_priority_over_mapreduce() {
let mut config = create_default_config();
config.command.dry_run = true;
config.mapreduce_config = Some(Arc::new(create_default_mapreduce_config()));
assert_eq!(detect_execution_mode(&config), ExecutionMode::DryRun);
}
#[test]
fn test_detect_mapreduce_mode() {
let mut config = create_default_config();
config.mapreduce_config = Some(Arc::new(create_default_mapreduce_config()));
assert_eq!(detect_execution_mode(&config), ExecutionMode::MapReduce);
}
#[test]
fn test_detect_iterative_mode_with_args() {
let mut config = create_default_config();
config.command.args = vec!["arg1".to_string(), "arg2".to_string()];
assert_eq!(detect_execution_mode(&config), ExecutionMode::Iterative);
}
#[test]
fn test_detect_iterative_mode_with_map() {
let mut config = create_default_config();
config.command.map = vec!["src/**/*.rs".to_string()];
assert_eq!(detect_execution_mode(&config), ExecutionMode::Iterative);
}
#[test]
fn test_detect_standard_mode() {
let config = create_default_config();
assert_eq!(detect_execution_mode(&config), ExecutionMode::Standard);
}
#[test]
fn test_mapreduce_takes_priority_over_iterative() {
let mut config = create_default_config();
config.mapreduce_config = Some(Arc::new(create_default_mapreduce_config()));
config.command.args = vec!["arg1".to_string()];
assert_eq!(detect_execution_mode(&config), ExecutionMode::MapReduce);
}
#[test]
fn test_execution_mode_display() {
assert_eq!(format!("{}", ExecutionMode::Standard), "Standard");
assert_eq!(format!("{}", ExecutionMode::MapReduce), "MapReduce");
assert_eq!(format!("{}", ExecutionMode::Iterative), "Iterative");
assert_eq!(format!("{}", ExecutionMode::DryRun), "DryRun");
}
#[test]
fn test_execution_mode_default() {
assert_eq!(ExecutionMode::default(), ExecutionMode::Standard);
}
#[test]
fn test_mode_detection_is_deterministic() {
let config = create_default_config();
let mode1 = detect_execution_mode(&config);
let mode2 = detect_execution_mode(&config);
assert_eq!(mode1, mode2, "Mode detection must be deterministic");
}
#[test]
fn test_mode_detection_deterministic_mapreduce() {
let mut config = create_default_config();
config.mapreduce_config = Some(Arc::new(create_default_mapreduce_config()));
let mode1 = detect_execution_mode(&config);
let mode2 = detect_execution_mode(&config);
assert_eq!(mode1, mode2, "Mode detection must be deterministic");
}
}