use super::*;
use notify::ErrorKind;
use std::fs;
use std::sync::mpsc;
use tempfile::tempdir;
#[test]
fn scenario_queue_overflow_is_announced_not_swallowed() {
let (tx, rx) = mpsc::channel();
tx.send(Ok(
Event::new(EventKind::Other).set_flag(notify::event::Flag::Rescan)
))
.unwrap();
drop(tx);
let mut raw = Vec::new();
assert!(
drain(&rx, &mut raw),
"the rescan flag is a loss announcement"
);
assert!(raw.is_empty(), "a rescan event carries no path to ingest");
}
#[test]
fn scenario_watch_descriptor_exhaustion_is_announced_not_swallowed() {
let (tx, rx) = mpsc::channel();
tx.send(Err(notify::Error::new(ErrorKind::MaxFilesWatch)))
.unwrap();
drop(tx);
let mut raw = Vec::new();
assert!(
drain(&rx, &mut raw),
"a backend error means events were lost"
);
assert!(raw.is_empty());
}
#[test]
fn a_quiet_channel_announces_no_loss() {
let (tx, rx) = mpsc::channel::<notify::Result<Event>>();
tx.send(Ok(Event::new(EventKind::Create(
notify::event::CreateKind::File,
))
.add_path(PathBuf::from("/r/steps/a/001/request.json"))))
.unwrap();
drop(tx);
let mut raw = Vec::new();
assert!(!drain(&rx, &mut raw), "an ordinary event is not a loss");
assert_eq!(raw.len(), 1);
}
#[test]
fn a_desync_leads_the_tick_as_a_change_on_the_root_itself() {
let root = Path::new("/w");
let ordinary = vec![Change {
path: PathBuf::from("/w/inbox/a/user-001.md"),
kind: ChangeKind::Touched,
}];
let led = lead_with_desync(root, true, ordinary.clone());
assert_eq!(led.len(), 2);
assert_eq!(led[0].path, root);
assert_eq!(led[0].kind, ChangeKind::Desynced);
assert_eq!(led[1], ordinary[0], "the real changes ride along behind it");
let alone = lead_with_desync(root, true, Vec::new());
assert_eq!(alone.len(), 1);
assert_eq!(alone[0].kind, ChangeKind::Desynced);
assert_eq!(lead_with_desync(root, false, ordinary.clone()), ordinary);
}
#[test]
fn a_healthy_watcher_never_claims_a_desync() {
let dir = tempdir().unwrap();
let root = dir.path().canonicalize().unwrap();
let watcher = Watcher::new(&root).unwrap();
assert!(
!watcher
.tick()
.iter()
.any(|c| c.kind == ChangeKind::Desynced)
);
}
#[test]
fn scenario_a_replaced_root_directory_leaves_a_deaf_watcher() {
let dir = tempdir().unwrap();
let root = dir.path().join("clone");
fs::create_dir_all(&root).unwrap();
let watcher = Watcher::new(&root).unwrap();
assert!(!watcher.is_stale(), "freshly armed on the live inode");
let fresh = crate::test_support::prepared_replacement(&root);
fs::remove_dir_all(&root).unwrap();
assert!(watcher.is_stale(), "a deleted root is a deaf watcher");
fs::rename(&fresh, &root).unwrap();
assert!(
watcher.is_stale(),
"and re-creating the path does not re-arm the old inode"
);
}