use std::fs;
use std::time::Instant;
use tempfile::TempDir;
#[tokio::test]
async fn benchmark_parallel_vs_serial_discovery() {
let temp_dir = TempDir::new().unwrap();
let test_root = temp_dir.path();
let subdirs = ["books", "classics", "poetry", "novels", "essays"];
for subdir in &subdirs {
fs::create_dir_all(test_root.join(subdir)).unwrap();
}
for i in 0..50 {
let subdir = &subdirs[i % subdirs.len()];
let file_name = format!("test-{i}-0.txt");
let file_path = test_root.join(subdir).join(&file_name);
let content = match i % 3 {
0 => "Short content with a sentence.".to_string(),
1 => format!("{} ", "Medium content with multiple sentences. ".repeat(20)),
_ => format!("{} ", "Long content with many sentences for testing purposes. ".repeat(100)),
};
fs::write(&file_path, content).unwrap();
}
let config = seams::discovery::DiscoveryConfig::default();
let start_time = Instant::now();
let serial_files = seams::discovery::collect_discovered_files(test_root, config.clone()).await.unwrap();
let serial_time = start_time.elapsed();
let start_time = Instant::now();
let parallel_files = seams::discovery::collect_discovered_files_parallel(test_root, config).await.unwrap();
let parallel_time = start_time.elapsed();
assert_eq!(serial_files.len(), parallel_files.len());
assert_eq!(serial_files.len(), 50);
println!("=== Directory Discovery Performance Benchmark ===");
println!("Files discovered: {}", serial_files.len());
println!("Serial discovery time: {:.2}ms", serial_time.as_millis());
println!("Parallel discovery time: {:.2}ms", parallel_time.as_millis());
if parallel_time < serial_time {
let improvement = serial_time.as_nanos() as f64 / parallel_time.as_nanos() as f64;
println!("Parallel discovery is {improvement:.2}x faster");
} else {
println!("Serial discovery was faster (overhead on small test set)");
}
println!("Directory structure: {} subdirectories", subdirs.len());
let valid_serial = serial_files.iter().filter(|f| f.error.is_none()).count();
let valid_parallel = parallel_files.iter().filter(|f| f.error.is_none()).count();
assert_eq!(valid_serial, valid_parallel);
assert_eq!(valid_serial, 50);
}
#[tokio::test]
async fn benchmark_parallel_discovery_large_directory() {
let temp_dir = TempDir::new().unwrap();
let test_root = temp_dir.path();
let depth = 5;
let files_per_dir = 10;
fn create_recursive_structure(base: &std::path::Path, depth: i32, files_per_dir: i32) -> i32 {
let mut file_count = 0;
if depth > 0 {
for i in 0..files_per_dir {
let file_name = format!("file-{i}-0.txt");
let file_path = base.join(&file_name);
fs::write(&file_path, format!("Content for file {i} at depth {depth}")).unwrap();
file_count += 1;
}
for i in 0..3 {
let subdir = base.join(format!("subdir-{i}"));
fs::create_dir_all(&subdir).unwrap();
file_count += create_recursive_structure(&subdir, depth - 1, files_per_dir);
}
}
file_count
}
let total_files = create_recursive_structure(test_root, depth, files_per_dir);
let config = seams::discovery::DiscoveryConfig::default();
let start_time = Instant::now();
let parallel_files = seams::discovery::collect_discovered_files_parallel(test_root, config.clone()).await.unwrap();
let parallel_time = start_time.elapsed();
let start_time = Instant::now();
let serial_files = seams::discovery::collect_discovered_files(test_root, config).await.unwrap();
let serial_time = start_time.elapsed();
assert_eq!(serial_files.len(), parallel_files.len());
assert_eq!(serial_files.len(), total_files as usize);
println!("=== Large Directory Discovery Performance Benchmark ===");
println!("Files discovered: {}", parallel_files.len());
println!("Directory depth: {depth}");
println!("Serial discovery time: {:.2}ms", serial_time.as_millis());
println!("Parallel discovery time: {:.2}ms", parallel_time.as_millis());
if parallel_time < serial_time {
let improvement = serial_time.as_nanos() as f64 / parallel_time.as_nanos() as f64;
println!("Parallel discovery is {improvement:.2}x faster");
} else {
let overhead = parallel_time.as_nanos() as f64 / serial_time.as_nanos() as f64;
println!("Serial discovery was {overhead:.2}x faster");
}
}
#[tokio::test]
async fn test_parallel_discovery_with_overlapped_pipeline() {
let temp_dir = TempDir::new().unwrap();
let test_root = temp_dir.path();
for i in 0..10 {
let file_name = format!("test-{i}-0.txt");
let file_path = test_root.join(&file_name);
let content = format!("Test file {i} content. This has sentences.");
fs::write(&file_path, content).unwrap();
}
let start_time = Instant::now();
let output = tokio::process::Command::new("cargo")
.arg("run")
.arg("--bin")
.arg("seams")
.arg("--")
.arg(test_root.to_str().unwrap())
.output()
.await
.expect("Failed to run seams binary");
let total_time = start_time.elapsed();
assert!(output.status.success(), "Overlapped pipeline with parallel discovery failed: {}",
String::from_utf8_lossy(&output.stderr));
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("Successfully processed: 10 files"));
assert!(stdout.contains("Overlapped discovery and processing complete"));
let mut aux_files_count = 0;
for entry in fs::read_dir(test_root).unwrap() {
let entry = entry.unwrap();
if entry.file_name().to_string_lossy().ends_with("_seams2.txt") {
aux_files_count += 1;
}
}
assert_eq!(aux_files_count, 10);
println!("=== Overlapped Pipeline with Parallel Discovery ===");
println!("Total time: {:.2}ms", total_time.as_millis());
println!("Files processed: 10");
println!("Aux files created: {aux_files_count}");
}