inotify-based folder watcher using the notify crate that detects new image files, ignores non-image files, and supports start/stop lifecycle. WatchFolder config struct for preset-linked watched directories.
116 lines
3.1 KiB
Rust
116 lines
3.1 KiB
Rust
use pixstrip_core::watcher::*;
|
|
use std::sync::mpsc;
|
|
|
|
#[test]
|
|
fn watch_folder_serialization() {
|
|
let folder = WatchFolder {
|
|
path: "/home/user/photos".into(),
|
|
preset_name: "Blog Photos".into(),
|
|
recursive: true,
|
|
active: true,
|
|
};
|
|
|
|
let json = serde_json::to_string(&folder).unwrap();
|
|
let deserialized: WatchFolder = serde_json::from_str(&json).unwrap();
|
|
assert_eq!(deserialized.preset_name, "Blog Photos");
|
|
assert!(deserialized.recursive);
|
|
}
|
|
|
|
#[test]
|
|
fn watcher_starts_and_stops() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let folder = WatchFolder {
|
|
path: dir.path().to_path_buf(),
|
|
preset_name: "Test".into(),
|
|
recursive: false,
|
|
active: true,
|
|
};
|
|
|
|
let watcher = FolderWatcher::new();
|
|
let (tx, _rx) = mpsc::channel();
|
|
|
|
watcher.start(&folder, tx).unwrap();
|
|
assert!(watcher.is_running());
|
|
|
|
watcher.stop();
|
|
// Give the thread time to see the stop signal
|
|
std::thread::sleep(std::time::Duration::from_millis(600));
|
|
assert!(!watcher.is_running());
|
|
}
|
|
|
|
#[test]
|
|
fn watcher_detects_new_image() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let folder = WatchFolder {
|
|
path: dir.path().to_path_buf(),
|
|
preset_name: "Test".into(),
|
|
recursive: false,
|
|
active: true,
|
|
};
|
|
|
|
let watcher = FolderWatcher::new();
|
|
let (tx, rx) = mpsc::channel();
|
|
|
|
watcher.start(&folder, tx).unwrap();
|
|
|
|
// Wait for watcher to be ready
|
|
std::thread::sleep(std::time::Duration::from_millis(200));
|
|
|
|
// Create an image file
|
|
let img_path = dir.path().join("new_photo.jpg");
|
|
std::fs::write(&img_path, b"fake jpeg data").unwrap();
|
|
|
|
// Wait and check for event
|
|
let event = rx.recv_timeout(std::time::Duration::from_secs(3));
|
|
watcher.stop();
|
|
|
|
match event {
|
|
Ok(WatchEvent::NewImage(path)) => {
|
|
assert_eq!(path, img_path);
|
|
}
|
|
Ok(WatchEvent::Error(e)) => panic!("Unexpected error: {}", e),
|
|
Err(_) => panic!("No event received within timeout"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn watcher_ignores_non_image_files() {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let folder = WatchFolder {
|
|
path: dir.path().to_path_buf(),
|
|
preset_name: "Test".into(),
|
|
recursive: false,
|
|
active: true,
|
|
};
|
|
|
|
let watcher = FolderWatcher::new();
|
|
let (tx, rx) = mpsc::channel();
|
|
|
|
watcher.start(&folder, tx).unwrap();
|
|
std::thread::sleep(std::time::Duration::from_millis(200));
|
|
|
|
// Create a non-image file
|
|
std::fs::write(dir.path().join("readme.txt"), b"text file").unwrap();
|
|
|
|
// Should not receive any event
|
|
let result = rx.recv_timeout(std::time::Duration::from_secs(1));
|
|
watcher.stop();
|
|
|
|
assert!(result.is_err(), "Should not receive event for non-image file");
|
|
}
|
|
|
|
#[test]
|
|
fn watcher_rejects_nonexistent_path() {
|
|
let folder = WatchFolder {
|
|
path: "/nonexistent/path/to/watch".into(),
|
|
preset_name: "Test".into(),
|
|
recursive: false,
|
|
active: true,
|
|
};
|
|
|
|
let watcher = FolderWatcher::new();
|
|
let (tx, _rx) = mpsc::channel();
|
|
|
|
assert!(watcher.start(&folder, tx).is_err());
|
|
}
|