extern crate env_logger; extern crate regex; extern crate ubiquity; #[macro_use] extern crate log; #[macro_use] extern crate generic_array; extern crate typenum; use typenum::U2; use regex::Regex; use std::fs; use std::io; use std::io::Write; use std::path::{Path, PathBuf}; use ubiquity::archive::Archive; use ubiquity::config::*; use ubiquity::detect; use ubiquity::propagate; use ubiquity::reconcile; fn set_up(name: &'static str) -> (Archive, SyncInfo) { let _ = env_logger::init(); let archive_path = PathBuf::from(format!("tests/replicas/{}/archive", name)); let a_path = PathBuf::from(format!("tests/replicas/{}/a", name)); let b_path = PathBuf::from(format!("tests/replicas/{}/b", name)); clean_directory(&archive_path).unwrap(); clean_directory(&a_path).unwrap(); clean_directory(&b_path).unwrap(); let config = SyncInfo::new(arr![PathBuf; a_path, b_path]); let archive = Archive::new(archive_path).unwrap(); return (archive, config); } #[test] fn test_differences_are_empty() { let (archive, config) = set_up("differences_are_empty"); let result = detect::find_updates( &archive, &mut detect::SearchDirectories::from_root(), &config, &detect::EmptyProgressCallback, ) .unwrap(); assert!(result.differences.is_empty()); } #[test] fn test_files_are_ignored() { let (archive, mut config) = set_up("files_are_ignored"); config.ignore.regexes.push(Regex::new(r"foo").unwrap()); config.ignore.paths.push("baz".to_owned()); fs::File::create(config.roots[0].join("foo")).unwrap(); fs::File::create(config.roots[0].join("something_contains_foo")).unwrap(); fs::create_dir(config.roots[0].join("baz")).unwrap(); let result = detect::find_updates( &archive, &mut detect::SearchDirectories::from_root(), &config, &detect::EmptyProgressCallback, ) .unwrap(); assert!(result.differences.is_empty()); } #[test] fn test_changes_are_detected() { let (archive, config) = set_up("changes_are_detected"); let mut test_document = fs::File::create(config.roots[1].join("Test Document")).unwrap(); write!(test_document, "Hello World").unwrap(); let result = detect::find_updates( &archive, &mut detect::SearchDirectories::from_root(), &config, &detect::EmptyProgressCallback, ) .unwrap(); assert_eq!(result.differences.len(), 1); assert_eq!(&result.differences[0].path, Path::new("Test Document")); } #[test] fn test_nested_differences_are_removed() { let (archive, config) = set_up("nested_differences_are_removed"); fs::create_dir(config.roots[0].join("baz")).unwrap(); fs::create_dir(config.roots[0].join("baz/qux")).unwrap(); fs::File::create(config.roots[0].join("baz/qux/cub")).unwrap(); let mut sd = detect::SearchDirectories::new( vec![Path::new("baz").into(), Path::new("baz/qux").into()], false, ); let result = detect::find_updates(&archive, &mut sd, &config, &detect::EmptyProgressCallback).unwrap(); assert_eq!(result.differences.len(), 1); assert_eq!(&result.differences[0].path, Path::new("baz")); } #[test] fn test_differences_are_resolved() { let (archive, config) = set_up("differences_are_resolved"); let ref sd = detect::SearchDirectories::from_root(); detect_and_resolve(&archive, &config, sd); // test creations fs::create_dir(config.roots[0].join("baz")).unwrap(); fs::File::create(config.roots[0].join("baz/cub")).unwrap(); info!("Testing after dir created"); detect_and_resolve(&archive, &config, sd); info!("Checking replicas are in sync"); let result = detect::find_updates( &archive, &mut sd.clone(), &config, &detect::EmptyProgressCallback, ) .unwrap(); assert_eq!(result.statistics.archive_additions, 0); assert_eq!(result.differences.len(), 0); // test deletions fs::remove_dir_all(config.roots[1].join("baz")).unwrap(); info!("Testing after dir removed"); detect_and_resolve(&archive, &config, sd); info!("Checking replicas are in sync"); let result = detect::find_updates( &archive, &mut sd.clone(), &config, &detect::EmptyProgressCallback, ) .unwrap(); assert_eq!(result.differences.len(), 0); assert_eq!(result.statistics.archive_additions, 0); } #[test] fn test_regex_forward_slash() { let r = regex::Regex::new(r"/target/").unwrap(); assert!(r.is_match("/Users/bob/awesome/target/foo")); assert!(!r.is_match("/Users/bob/awesome/target")); } fn detect_and_resolve( archive: &Archive, config: &SyncInfo, search_directories: &detect::SearchDirectories, ) { let result = detect::find_updates( archive, &mut search_directories.clone(), config, &detect::EmptyProgressCallback, ) .unwrap(); info!("{} differences", result.differences.len()); for difference in result.differences { let operation = reconcile::guess_operation(&difference); info!("difference {:?}: {:?}", difference.path, operation); if let reconcile::Operation::PropagateFromMaster(master) = operation { propagate::propagate( &difference, master, &archive, &propagate::DefaultPropagationOptions, &propagate::EmptyProgressCallback, ) .unwrap(); } } } fn clean_directory(p: &Path) -> io::Result<()> { if !p.exists() { fs::create_dir_all(p)?; return Ok(()); } for entry in fs::read_dir(p)? { let entry = entry?; if entry.metadata()?.is_dir() { fs::remove_dir_all(entry.path())?; } else { fs::remove_file(entry.path())?; } } Ok(()) }