use std::fs::{self, File};
use std::io::{self, Write};
use tempfile::TempDir;
const MB: u64 = 1024 * 1024;
const GB: u64 = 1024 * MB;
fn create_large_file(path: &std::path::Path, size: u64) -> io::Result<()> {
let mut file = File::create(path)?;
let block_size = 1024 * 1024; let mut block = vec![0u8; block_size];
for (i, byte) in block.iter_mut().enumerate() {
*byte = (i % 256) as u8;
}
let full_blocks = size / block_size as u64;
let remainder = size % block_size as u64;
for _ in 0..full_blocks {
file.write_all(&block)?;
}
if remainder > 0 {
file.write_all(&block[..remainder as usize])?;
}
file.sync_all()?;
Ok(())
}
#[test]
#[ignore] fn test_sync_100mb_file() {
let source_dir = TempDir::new().unwrap();
let dest_dir = TempDir::new().unwrap();
let source_file = source_dir.path().join("large.dat");
let size = 100 * MB;
println!("Creating 100MB test file...");
create_large_file(&source_file, size).unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_sy"))
.arg(source_dir.path())
.arg(dest_dir.path())
.output()
.expect("Failed to execute sy");
assert!(output.status.success(), "Sync failed: {:?}", String::from_utf8_lossy(&output.stderr));
let dest_file = dest_dir.path().join("large.dat");
assert!(dest_file.exists(), "Destination file not created");
let dest_size = fs::metadata(&dest_file).unwrap().len();
assert_eq!(dest_size, size, "File size mismatch");
println!("✅ 100MB file synced successfully");
}
#[test]
#[ignore] fn test_sync_500mb_file() {
let source_dir = TempDir::new().unwrap();
let dest_dir = TempDir::new().unwrap();
let source_file = source_dir.path().join("large.dat");
let size = 500 * MB;
println!("Creating 500MB test file...");
create_large_file(&source_file, size).unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_sy"))
.arg(source_dir.path())
.arg(dest_dir.path())
.output()
.expect("Failed to execute sy");
assert!(output.status.success(), "Sync failed: {:?}", String::from_utf8_lossy(&output.stderr));
let dest_file = dest_dir.path().join("large.dat");
assert!(dest_file.exists(), "Destination file not created");
let dest_size = fs::metadata(&dest_file).unwrap().len();
assert_eq!(dest_size, size, "File size mismatch");
println!("✅ 500MB file synced successfully");
}
#[test]
#[ignore] fn test_sync_1gb_file() {
let source_dir = TempDir::new().unwrap();
let dest_dir = TempDir::new().unwrap();
let source_file = source_dir.path().join("large.dat");
let size = GB;
println!("Creating 1GB test file...");
create_large_file(&source_file, size).unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_sy"))
.arg(source_dir.path())
.arg(dest_dir.path())
.arg("-v")
.output()
.expect("Failed to execute sy");
assert!(output.status.success(), "Sync failed: {:?}", String::from_utf8_lossy(&output.stderr));
let dest_file = dest_dir.path().join("large.dat");
assert!(dest_file.exists(), "Destination file not created");
let dest_size = fs::metadata(&dest_file).unwrap().len();
assert_eq!(dest_size, size, "File size mismatch");
println!("✅ 1GB file synced successfully");
}
#[test]
#[ignore] #[cfg(target_os = "linux")] fn test_sync_1gb_sparse_file() {
let source_dir = TempDir::new().unwrap();
let dest_dir = TempDir::new().unwrap();
let source_file = source_dir.path().join("sparse.dat");
let size = GB;
println!("Creating 1GB sparse file...");
let file = File::create(&source_file).unwrap();
file.set_len(size).unwrap(); drop(file);
let mut file = File::options().write(true).open(&source_file).unwrap();
file.write_all(&vec![0xAA; MB as usize]).unwrap();
use std::io::Seek;
file.seek(std::io::SeekFrom::Start(size - MB)).unwrap();
file.write_all(&vec![0xBB; MB as usize]).unwrap();
file.sync_all().unwrap();
drop(file);
let source_allocated = fs::metadata(&source_file).unwrap().len();
println!("Source file: logical={}MB, allocated={}MB", size / MB, source_allocated / MB);
let output = std::process::Command::new(env!("CARGO_BIN_EXE_sy"))
.arg(source_dir.path())
.arg(dest_dir.path())
.output()
.expect("Failed to execute sy");
assert!(output.status.success(), "Sync failed: {:?}", String::from_utf8_lossy(&output.stderr));
let dest_file = dest_dir.path().join("sparse.dat");
assert!(dest_file.exists(), "Destination file not created");
let dest_size = fs::metadata(&dest_file).unwrap().len();
assert_eq!(dest_size, size, "Logical size mismatch");
println!("✅ 1GB sparse file synced successfully");
}
#[test]
#[ignore] fn test_progress_accuracy_100mb() {
let source_dir = TempDir::new().unwrap();
let dest_dir = TempDir::new().unwrap();
let source_file = source_dir.path().join("large.dat");
let size = 100 * MB;
println!("Creating 100MB test file for progress testing...");
create_large_file(&source_file, size).unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_sy"))
.arg(source_dir.path())
.arg(dest_dir.path())
.arg("--json")
.output()
.expect("Failed to execute sy");
assert!(output.status.success(), "Sync failed: {:?}", String::from_utf8_lossy(&output.stderr));
let stdout = String::from_utf8_lossy(&output.stdout);
let mut total_bytes = 0u64;
for line in stdout.lines() {
if let Ok(event) = serde_json::from_str::<serde_json::Value>(line) {
let event_type = event["type"].as_str().unwrap_or("");
if (event_type == "create" || event_type == "update")
&& let Some(bytes) = event["bytes_transferred"].as_u64()
{
total_bytes += bytes;
}
}
}
let tolerance = size / 100; assert!(
total_bytes >= size - tolerance && total_bytes <= size + tolerance,
"Progress tracking inaccurate: expected ~{}, got {}",
size,
total_bytes
);
println!("✅ Progress tracking accurate for 100MB file");
}
#[test]
#[ignore] fn test_idempotent_sync_100mb() {
let source_dir = TempDir::new().unwrap();
let dest_dir = TempDir::new().unwrap();
let source_file = source_dir.path().join("large.dat");
let size = 100 * MB;
println!("Creating 100MB test file...");
create_large_file(&source_file, size).unwrap();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_sy"))
.arg(source_dir.path())
.arg(dest_dir.path())
.output()
.expect("Failed to execute sy");
assert!(output.status.success(), "First sync failed");
let start = std::time::Instant::now();
let output = std::process::Command::new(env!("CARGO_BIN_EXE_sy"))
.arg(source_dir.path())
.arg(dest_dir.path())
.output()
.expect("Failed to execute sy");
let elapsed = start.elapsed();
assert!(output.status.success(), "Second sync failed");
assert!(elapsed.as_secs() < 2, "Idempotent sync too slow: {:?}", elapsed);
println!("✅ Idempotent sync of 100MB file: {:?}", elapsed);
}