#[cfg(test)]
mod tests {
use std::io::Write;
use std::time::Duration;
use tempfile::NamedTempFile;
use tokio::sync::mpsc;
use tokio::time::timeout;
use crate::tail::engine::{poll, Event};
async fn next_event(
rx: &mut mpsc::Receiver<Event>,
max: Duration,
) -> Option<Event> {
timeout(max, rx.recv()).await.ok().flatten()
}
#[tokio::test]
async fn detects_growth() {
let mut tmp = NamedTempFile::new().unwrap();
writeln!(tmp, "first").unwrap();
tmp.flush().unwrap();
let path = tmp.path().to_path_buf();
let (tx, mut rx) = mpsc::channel(8);
let handle = tokio::spawn(poll::run_every(
vec![path.clone()],
tx,
Duration::from_millis(30),
));
writeln!(tmp, "second").unwrap();
tmp.flush().unwrap();
let event = next_event(&mut rx, Duration::from_secs(1)).await;
handle.abort();
assert!(matches!(event, Some(Event::Grew(p)) if p == path));
}
#[tokio::test]
async fn detects_truncation() {
let mut tmp = NamedTempFile::new().unwrap();
writeln!(tmp, "hello").unwrap();
tmp.flush().unwrap();
let path = tmp.path().to_path_buf();
let (tx, mut rx) = mpsc::channel(8);
let handle = tokio::spawn(poll::run_every(
vec![path.clone()],
tx,
Duration::from_millis(30),
));
tmp.as_file().set_len(0).unwrap();
let event = next_event(&mut rx, Duration::from_secs(1)).await;
handle.abort();
assert!(matches!(event, Some(Event::Shrunk(p)) if p == path));
}
#[tokio::test]
async fn missing_path_reports_gone() {
let tmp = NamedTempFile::new().unwrap();
let path = tmp.path().to_path_buf();
drop(tmp);
let (tx, mut rx) = mpsc::channel(8);
let handle = tokio::spawn(poll::run_every(
vec![path.clone()],
tx,
Duration::from_millis(30),
));
let event = next_event(&mut rx, Duration::from_secs(1)).await;
handle.abort();
assert!(matches!(event, Some(Event::Gone(p)) if p == path));
}
}