use crate::config::OrchestratorConfig;
use crate::parallel::ParallelExecutor;
use std::sync::Arc;
use tempfile::TempDir;
fn create_test_config() -> OrchestratorConfig {
OrchestratorConfig {
apply_command: Some("echo apply {change_id}".to_string()),
archive_command: Some("echo archive {change_id}".to_string()),
analyze_command: Some("echo analyze".to_string()),
acceptance_command: Some("echo acceptance".to_string()),
resolve_command: Some("echo resolve".to_string()),
..Default::default()
}
}
#[tokio::test]
async fn test_auto_resolve_counter_reduces_available_slots() {
let temp_dir = TempDir::new().unwrap();
let repo_root = temp_dir.path().to_path_buf();
let config = create_test_config();
let executor = ParallelExecutor::new(repo_root.clone(), config.clone(), None);
let auto_resolve_counter = executor.get_auto_resolve_counter();
assert_eq!(
auto_resolve_counter.load(std::sync::atomic::Ordering::SeqCst),
0,
"Auto resolve counter should start at 0"
);
auto_resolve_counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
assert_eq!(
auto_resolve_counter.load(std::sync::atomic::Ordering::SeqCst),
1,
"Auto resolve counter should be 1 after increment"
);
auto_resolve_counter.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
assert_eq!(
auto_resolve_counter.load(std::sync::atomic::Ordering::SeqCst),
0,
"Auto resolve counter should return to 0 after completion"
);
}
#[tokio::test]
async fn test_multiple_auto_resolves_consume_multiple_slots() {
let temp_dir = TempDir::new().unwrap();
let repo_root = temp_dir.path().to_path_buf();
let config = create_test_config();
let executor = ParallelExecutor::new(repo_root.clone(), config.clone(), None);
let auto_resolve_counter = executor.get_auto_resolve_counter();
auto_resolve_counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
auto_resolve_counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
assert_eq!(
auto_resolve_counter.load(std::sync::atomic::Ordering::SeqCst),
2,
"Auto resolve counter should be 2 for concurrent resolves"
);
auto_resolve_counter.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
assert_eq!(
auto_resolve_counter.load(std::sync::atomic::Ordering::SeqCst),
1,
"Auto resolve counter should be 1 after one completes"
);
auto_resolve_counter.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
assert_eq!(
auto_resolve_counter.load(std::sync::atomic::Ordering::SeqCst),
0,
"Auto resolve counter should be 0 after all complete"
);
}
#[test]
fn test_auto_resolve_counter_is_thread_safe() {
let temp_dir = TempDir::new().unwrap();
let repo_root = temp_dir.path().to_path_buf();
let config = create_test_config();
let executor = ParallelExecutor::new(repo_root.clone(), config.clone(), None);
let counter = executor.get_auto_resolve_counter();
let handles: Vec<_> = (0..10)
.map(|_| {
let counter_clone = counter.clone();
std::thread::spawn(move || {
for _ in 0..100 {
counter_clone.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
counter_clone.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
}
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
assert_eq!(
counter.load(std::sync::atomic::Ordering::SeqCst),
0,
"Counter should be 0 after concurrent increment/decrement operations"
);
}
#[tokio::test]
async fn test_combined_manual_and_auto_resolve_slots() {
let temp_dir = TempDir::new().unwrap();
let repo_root = temp_dir.path().to_path_buf();
let config = create_test_config();
let mut executor = ParallelExecutor::new(repo_root.clone(), config.clone(), None);
let manual_resolve_counter = Arc::new(std::sync::atomic::AtomicUsize::new(0));
executor.set_manual_resolve_counter(manual_resolve_counter.clone());
let auto_resolve_counter = executor.get_auto_resolve_counter();
manual_resolve_counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
auto_resolve_counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
assert_eq!(
manual_resolve_counter.load(std::sync::atomic::Ordering::SeqCst),
1,
"Manual resolve counter should be 1"
);
assert_eq!(
auto_resolve_counter.load(std::sync::atomic::Ordering::SeqCst),
1,
"Auto resolve counter should be 1"
);
manual_resolve_counter.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
assert_eq!(
manual_resolve_counter.load(std::sync::atomic::Ordering::SeqCst),
0,
"Manual resolve counter should be 0 after completion"
);
assert_eq!(
auto_resolve_counter.load(std::sync::atomic::Ordering::SeqCst),
1,
"Auto resolve counter should still be 1"
);
auto_resolve_counter.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
assert_eq!(
auto_resolve_counter.load(std::sync::atomic::Ordering::SeqCst),
0,
"Auto resolve counter should be 0 after completion"
);
}