use night::common::types::{MissionConfig, TaskConfig, TaskStatus};
use night::{get_task_info, init, run, Mission, Result};
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use std::time::Instant;
use tempfile::TempDir;
use tokio;
use tokio::time::Duration;
use uuid::Uuid;
fn create_temp_config_file(config: &MissionConfig) -> Result<(TempDir, PathBuf)> {
let temp_dir = tempfile::tempdir()?;
let config_path = temp_dir.path().join("config.json");
let config_json = serde_json::to_string_pretty(&config)?;
fs::write(&config_path, config_json)?;
Ok((temp_dir, config_path))
}
fn create_complex_test_config() -> (MissionConfig, HashMap<char, Uuid>) {
let mut task_ids = HashMap::new();
let task_names = vec!['A', 'B', 'C', 'D', 'E'];
for &name in &task_names {
task_ids.insert(name, Uuid::new_v4());
}
let tasks = vec![
TaskConfig {
name: "Task A".to_string(),
id: task_ids[&'A'],
command: "echo Task A".to_string(),
is_periodic: false,
interval: "1".to_string(),
importance: 1,
dependencies: vec![],
},
TaskConfig {
name: "Task B".to_string(),
id: task_ids[&'B'],
command: "echo Task B".to_string(),
is_periodic: false,
interval: "1".to_string(),
importance: 1,
dependencies: vec![task_ids[&'A']],
},
TaskConfig {
name: "Task C".to_string(),
id: task_ids[&'C'],
command: "echo Task C".to_string(),
is_periodic: false,
interval: "1".to_string(),
importance: 1,
dependencies: vec![task_ids[&'B'], task_ids[&'E']],
},
TaskConfig {
name: "Task D".to_string(),
id: task_ids[&'D'],
command: "echo Task D".to_string(),
is_periodic: false,
interval: "1".to_string(),
importance: 1,
dependencies: vec![task_ids[&'C']],
},
TaskConfig {
name: "Task E".to_string(),
id: task_ids[&'E'],
command: "echo Task E".to_string(),
is_periodic: false,
interval: "1".to_string(),
importance: 1,
dependencies: vec![task_ids[&'A']],
},
];
(
MissionConfig {
name: "Complex Test Mission".to_string(),
tasks,
},
task_ids,
)
}
async fn wait_for_tasks_completion(
mission: &Mission,
task_ids: &HashMap<char, Uuid>,
max_wait: Duration,
) -> Result<()> {
let start = Instant::now();
while start.elapsed() < max_wait {
let mut all_completed = true;
for (&task_char, &id) in task_ids {
match get_task_info(mission, id).await {
Ok(info) => {
log::debug!("Task {} ({}): status: {:?}", task_char, id, info.status);
if info.status != TaskStatus::Completed {
all_completed = false;
break;
}
}
Err(e) => {
log::error!(
"Failed to get info for task {} ({}): {:?}",
task_char,
id,
e
);
all_completed = false;
break;
}
}
}
if all_completed {
return Ok(());
}
tokio::time::sleep(Duration::from_millis(100)).await;
}
Ok(())
}
#[tokio::test]
async fn test_complex_mission_initialization() -> Result<()> {
let (config, _) = create_complex_test_config();
let (_temp_dir, config_path) = create_temp_config_file(&config)?;
let mission = init(config_path.to_str().unwrap()).await?;
assert_eq!(mission.config.name, "Complex Test Mission");
assert_eq!(mission.config.tasks.len(), 5);
Ok(())
}
#[tokio::test]
async fn test_complex_mission_execution() -> Result<()> {
let (config, task_ids) = create_complex_test_config();
let (_temp_dir, config_path) = create_temp_config_file(&config)?;
let mission = init(config_path.to_str().unwrap()).await?;
let mission_clone = mission.clone();
tokio::spawn(async move {
run(&mission_clone).await.unwrap();
});
wait_for_tasks_completion(&mission, &task_ids, Duration::from_secs(10)).await?;
for (task_char, &task_id) in &task_ids {
let info = get_task_info(&mission, task_id).await?;
assert_eq!(
info.status,
TaskStatus::Completed,
"Task {} did not complete",
task_char
);
}
let a_order = get_task_info(&mission, task_ids[&'A'])
.await?
.execution_order
.unwrap();
let b_order = get_task_info(&mission, task_ids[&'B'])
.await?
.execution_order
.unwrap();
let c_order = get_task_info(&mission, task_ids[&'C'])
.await?
.execution_order
.unwrap();
let d_order = get_task_info(&mission, task_ids[&'D'])
.await?
.execution_order
.unwrap();
let e_order = get_task_info(&mission, task_ids[&'E'])
.await?
.execution_order
.unwrap();
assert!(a_order < b_order, "Task A should execute before Task B");
assert!(a_order < e_order, "Task A should execute before Task E");
assert!(b_order < c_order, "Task B should execute before Task C");
assert!(e_order < c_order, "Task E should execute before Task C");
assert!(c_order < d_order, "Task C should execute before Task D");
Ok(())
}