Add file watcher for watch folder functionality
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.
This commit is contained in:
115
pixstrip-core/tests/watcher_tests.rs
Normal file
115
pixstrip-core/tests/watcher_tests.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
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());
|
||||
}
|
||||
Reference in New Issue
Block a user